Add NES emulator example

This commit is contained in:
Micky 2022-11-26 14:16:55 +08:00
parent 876badcbff
commit 7153e8e0fd
192 changed files with 45783 additions and 5 deletions

19
example/nes/.clang-format Normal file
View File

@ -0,0 +1,19 @@
---
# ref: https://clang.llvm.org/docs/ClangFormatStyleOptions.html
# 语言: None, Cpp, Java, JavaScript, ObjC, Proto, TableGen, TextProto
Language: Cpp
# BasedOnStyle: LLVM
# 每行字符的限制0表示没有限制
ColumnLimit: 150
# 预处理器指令的缩进样式
IndentPPDirectives: None
MacroBlockBegin: Without
# 宏定义对齐
AlignConsecutiveMacros: AcrossEmptyLinesAndComments
# Enabled: true
# AcrossEmptyLines: false
# AcrossComments: true

5
example/nes/.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
.pio
.vscode/.browse.c_cpp.db*
.vscode/c_cpp_properties.json
.vscode/launch.json
.vscode/ipch

111
example/nes/controller.cpp Normal file
View File

@ -0,0 +1,111 @@
#include "pin_config.h"
#include <Arduino.h>
/* controller is GPIO */
#if defined(HW_CONTROLLER_GPIO)
extern "C" void controller_init() {
#if defined(HW_CONTROLLER_GPIO_ANALOG_JOYSTICK)
pinMode(HW_CONTROLLER_GPIO_UP_DOWN, INPUT);
pinMode(HW_CONTROLLER_GPIO_LEFT_RIGHT, INPUT);
#else /* !defined(HW_CONTROLLER_GPIO_ANALOG_JOYSTICK) */
pinMode(HW_CONTROLLER_GPIO_UP, INPUT_PULLUP);
pinMode(HW_CONTROLLER_GPIO_DOWN, INPUT_PULLUP);
pinMode(HW_CONTROLLER_GPIO_LEFT, INPUT_PULLUP);
pinMode(HW_CONTROLLER_GPIO_RIGHT, INPUT_PULLUP);
#endif /* !defined(HW_CONTROLLER_GPIO_ANALOG_JOYSTICK) */
pinMode(HW_CONTROLLER_GPIO_SELECT, INPUT_PULLUP);
pinMode(HW_CONTROLLER_GPIO_START, INPUT_PULLUP);
pinMode(HW_CONTROLLER_GPIO_A, INPUT_PULLUP);
pinMode(HW_CONTROLLER_GPIO_B, INPUT_PULLUP);
pinMode(HW_CONTROLLER_GPIO_X, INPUT_PULLUP);
pinMode(HW_CONTROLLER_GPIO_Y, INPUT_PULLUP);
}
extern "C" uint32_t controller_read_input() {
uint32_t u, d, l, r, s, t, a, b, x, y;
#if defined(HW_CONTROLLER_GPIO_ANALOG_JOYSTICK)
#if defined(HW_CONTROLLER_GPIO_REVERSE_UP)
int joyY = 4095 - analogRead(HW_CONTROLLER_GPIO_UP_DOWN);
#else /* !defined(HW_CONTROLLER_GPIO_REVERSE_UD) */
int joyY = analogRead(HW_CONTROLLER_GPIO_UP_DOWN);
#endif /* !defined(HW_CONTROLLER_GPIO_REVERSE_UD) */
#if defined(HW_CONTROLLER_GPIO_REVERSE_LF)
int joyX = 4095 - analogRead(HW_CONTROLLER_GPIO_LEFT_RIGHT);
#else /* !defined(HW_CONTROLLER_GPIO_REVERSE_LF) */
int joyX = analogRead(HW_CONTROLLER_GPIO_LEFT_RIGHT);
#endif /* !defined(HW_CONTROLLER_GPIO_REVERSE_LF) */
if (joyY > 2048 + 1024) {
u = 1;
d = 0;
} else if (joyY < 1024) {
u = 0;
d = 1;
} else {
u = 1;
d = 1;
}
if (joyX > 2048 + 1024) {
l = 1;
r = 0;
} else if (joyX < 1024) {
l = 0;
r = 1;
} else {
l = 1;
r = 1;
}
#else /* !defined(HW_CONTROLLER_GPIO_ANALOG_JOYSTICK) */
u = digitalRead(HW_CONTROLLER_GPIO_UP);
d = digitalRead(HW_CONTROLLER_GPIO_DOWN);
l = digitalRead(HW_CONTROLLER_GPIO_LEFT);
r = digitalRead(HW_CONTROLLER_GPIO_RIGHT);
#endif /* !defined(HW_CONTROLLER_GPIO_ANALOG_JOYSTICK) */
s = digitalRead(HW_CONTROLLER_GPIO_SELECT);
t = digitalRead(HW_CONTROLLER_GPIO_START);
a = digitalRead(HW_CONTROLLER_GPIO_A);
b = digitalRead(HW_CONTROLLER_GPIO_B);
x = digitalRead(HW_CONTROLLER_GPIO_X);
y = digitalRead(HW_CONTROLLER_GPIO_Y);
return 0xFFFFFFFF ^ ((!u << 0) | (!d << 1) | (!l << 2) | (!r << 3) | (!s << 4) | (!t << 5) | (!a << 6) | (!b << 7) | (!x << 8) | (!y << 9));
}
#elif defined(HW_CONTROLLER_DABBLE_APP)
#include <DabbleESP32.h>
extern "C" void controller_init() { Dabble.begin("t-Display-S3-NES"); }
extern "C" uint32_t controller_read_input() {
uint32_t u, d, l, r, s, t, a, b, x, y;
Dabble.processInput();
d = GamePad.isUpPressed();
u = GamePad.isDownPressed();
r = GamePad.isLeftPressed();
l = GamePad.isRightPressed();
s = !GamePad.isSelectPressed();
t = !GamePad.isStartPressed();
y = !GamePad.isTrianglePressed();
b = !GamePad.isCrossPressed();
x = !GamePad.isSquarePressed();
a = !GamePad.isCirclePressed();
return 0xFFFFFFFF ^ ((!u << 0) | (!d << 1) | (!l << 2) | (!r << 3) | (!s << 4) | (!t << 5) | (!a << 6) | (!b << 7) | (!x << 8) | (!y << 9));
}
#else /* no controller defined */
extern "C" void controller_init() { Serial.printf("GPIO controller disabled in menuconfig; no input enabled.\n"); }
extern "C" uint32_t controller_read_input() { return 0xFFFFFFFF; }
#endif /* no controller defined */

BIN
example/nes/data/Chase.nes Normal file

Binary file not shown.

View File

@ -0,0 +1,4 @@
This is an example game that is developed for my article Programming NES games in C. The article itself is located at my website in the Articles section, to make things simpler in case of possible updates.
http://shiru.untergrund.net
mailto:shiru@mail.ru

6802
example/nes/img_logo.h Normal file

File diff suppressed because it is too large Load Diff

114
example/nes/nes.ino Normal file
View File

@ -0,0 +1,114 @@
#include <esp_task_wdt.h>
#include <esp_wifi.h>
#include "Arduino.h"
#include "img_logo.h"
#include "pin_config.h"
#include "Arduino_GFX_Library.h" /* https://github.com/moononournation/Arduino_GFX */
#include <FS.h>
#include <SPIFFS.h>
extern "C" {
#include <nes/nes.h> /* https://github.com/moononournation/arduino-nofrendo */
#include <nofrendo.h>
}
#define FSROOT "/fs"
Arduino_DataBus *bus = new Arduino_ESP32LCD8(7 /* DC */, 6 /* CS */, 8 /* WR */, 9 /* RD */, 39 /* D0 */, 40 /* D1 */, 41 /* D2 */, 42 /* D3 */,
45 /* D4 */, 46 /* D5 */, 47 /* D6 */, 48 /* D7 */);
Arduino_GFX *gfx = new Arduino_ST7789(bus, 5 /* RST */, 0 /* rotation */, true /* IPS */, 170 /* width */, 320 /* height */, 35 /* col offset 1 */,
0 /* row offset 1 */, 35 /* col offset 2 */, 0 /* row offset 2 */);
static int16_t frame_x, frame_y;
extern uint16_t myPalette[];
int16_t bg_color;
void setup() {
pinMode(PIN_POWER_ON, OUTPUT);
digitalWrite(PIN_POWER_ON, HIGH);
ledcSetup(0, 2000, 8);
ledcAttachPin(PIN_LCD_BL, 0);
ledcWrite(0, 255); /* Screen brightness can be modified by adjusting this parameter. (0-255) */
Serial.begin(115200);
Serial.println("Hello T-Display-S3 NES DEMO");
// turn off WiFi
esp_wifi_deinit();
// disable Core 0 WDT
TaskHandle_t idle_0 = xTaskGetIdleTaskHandleForCPU(0);
esp_task_wdt_delete(idle_0);
gfx->begin();
gfx->setRotation(1);
bg_color = gfx->color565(24, 28, 24); // DARK DARK GREY
gfx->draw16bitRGBBitmap(0, 0, (uint16_t *)img_logo, 320, 172);
delay(2000);
SPIFFS.begin(true, FSROOT);
FS filesystem = SPIFFS;
// find first rom file (*.nes)
File root = filesystem.open("/");
char *argv[1];
if (!root) {
Serial.println("Filesystem mount failed!");
} else {
bool foundRom = false;
File file = root.openNextFile();
while (file) {
if (file.isDirectory()) {
// skip
} else {
char *filename = (char *)file.name();
int8_t len = strlen(filename);
if (strstr(strlwr(filename + (len - 4)), ".nes")) {
foundRom = true;
char fullFilename[256];
sprintf(fullFilename, "%s/%s", FSROOT, filename);
Serial.println(fullFilename);
argv[0] = fullFilename;
break;
}
}
file = root.openNextFile();
}
if (!foundRom) {
Serial.println("Failed to find rom file, please copy rom file to data folder and upload with \"ESP32 Sketch Data Upload\"");
argv[0] = "/";
}
Serial.println("NoFrendo start!\n");
nofrendo_main(1, argv);
Serial.println("NoFrendo end!\n");
}
}
void loop(void) { delay(1); }
extern "C" void display_init() {
frame_x = (gfx->width() - NES_SCREEN_WIDTH) / 2;
frame_y = 35;
}
extern "C" void display_write_frame(const uint8_t *data[]) {
gfx->startWrite();
bus->writeC8D16D16(0x2A, frame_x, frame_x + NES_SCREEN_WIDTH - 1);
bus->writeC8D16D16(0x2B, frame_y, frame_y + NES_SCREEN_HEIGHT - 1);
bus->writeCommand(0x2c);
for (int32_t i = 0; i < NES_SCREEN_HEIGHT; i++) {
if ((i % 7) < 5)
bus->writeIndexedPixels((uint8_t *)(data[i]), myPalette, NES_SCREEN_WIDTH);
}
gfx->endWrite();
}
extern "C" void display_clear() { gfx->fillScreen(bg_color); }

367
example/nes/osd.c Normal file
View File

@ -0,0 +1,367 @@
/* start rewrite from: https://github.com/espressif/esp32-nesemu.git */
#include <freertos/FreeRTOS.h>
#include <freertos/timers.h>
#include <freertos/task.h>
#include <freertos/queue.h>
#include <driver/i2s.h>
#include <esp_heap_caps.h>
#include <noftypes.h>
#include <event.h>
#include <gui.h>
#include <log.h>
#include <nes/nes.h>
#include <nes/nes_pal.h>
#include <nes/nesinput.h>
#include <nofconfig.h>
#include <osd.h>
TimerHandle_t timer;
/* memory allocation */
extern void *mem_alloc(int size, bool prefer_fast_memory)
{
if (prefer_fast_memory) {
return heap_caps_malloc(size, MALLOC_CAP_8BIT);
} else {
return heap_caps_malloc_prefer(size, MALLOC_CAP_SPIRAM, MALLOC_CAP_DEFAULT);
}
}
/* audio */
#define DEFAULT_SAMPLERATE 22050
#if defined(HW_AUDIO)
#define DEFAULT_FRAGSIZE 1024
static void (*audio_callback)(void *buffer, int length) = NULL;
QueueHandle_t queue;
static int16_t *audio_frame;
static int osd_init_sound(void)
{
audio_frame = NOFRENDO_MALLOC(4 * DEFAULT_FRAGSIZE);
i2s_config_t cfg = {
#if defined(HW_AUDIO_EXTDAC)
.mode = I2S_MODE_MASTER | I2S_MODE_TX,
#else /* !defined(HW_AUDIO_EXTDAC) */
.mode = I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN,
#endif /* !defined(HW_AUDIO_EXTDAC) */
.sample_rate = DEFAULT_SAMPLERATE,
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
#if defined(HW_AUDIO_EXTDAC)
.communication_format = I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB,
#else /* !defined(HW_AUDIO_EXTDAC) */
.communication_format = I2S_COMM_FORMAT_PCM | I2S_COMM_FORMAT_I2S_MSB,
#endif /* !defined(HW_AUDIO_EXTDAC) */
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
.dma_buf_count = 6,
.dma_buf_len = 512,
.use_apll = false,
};
i2s_driver_install(I2S_NUM_0, &cfg, 2, &queue);
#if defined(HW_AUDIO_EXTDAC)
i2s_pin_config_t pins = {
.bck_io_num = HW_AUDIO_EXTDAC_BCLK,
.ws_io_num = HW_AUDIO_EXTDAC_WCLK,
.data_out_num = HW_AUDIO_EXTDAC_DOUT,
.data_in_num = I2S_PIN_NO_CHANGE,
};
i2s_set_pin(I2S_NUM_0, &pins);
#else /* !defined(HW_AUDIO_EXTDAC) */
i2s_set_pin(I2S_NUM_0, NULL);
i2s_set_dac_mode(I2S_DAC_CHANNEL_BOTH_EN);
#endif /* !defined(HW_AUDIO_EXTDAC) */
i2s_zero_dma_buffer(I2S_NUM_0);
audio_callback = NULL;
return 0;
}
static void osd_stopsound(void)
{
audio_callback = NULL;
}
static void do_audio_frame()
{
int left = DEFAULT_SAMPLERATE / NES_REFRESH_RATE;
while (left) {
int n = DEFAULT_FRAGSIZE;
if (n > left)
n = left;
audio_callback(audio_frame, n); //get more data
//16 bit mono -> 32-bit (16 bit r+l)
int16_t *mono_ptr = audio_frame + n;
int16_t *stereo_ptr = audio_frame + n + n;
int i = n;
while (i--) {
#if defined(HW_AUDIO_EXTDAC)
int16_t a = (*(--mono_ptr) >> 2);
*(--stereo_ptr) = a;
*(--stereo_ptr) = a;
#else /* !defined(HW_AUDIO_EXTDAC) */
int16_t a = (*(--mono_ptr) >> 3);
*(--stereo_ptr) = 0x8000 + a;
*(--stereo_ptr) = 0x8000 - a;
#endif /* !defined(HW_AUDIO_EXTDAC) */
}
size_t i2s_bytes_write;
i2s_write(I2S_NUM_0, (const char *)audio_frame, 4 * n, &i2s_bytes_write, portMAX_DELAY);
left -= i2s_bytes_write / 4;
}
}
void osd_setsound(void (*playfunc)(void *buffer, int length))
{
//Indicates we should call playfunc() to get more data.
audio_callback = playfunc;
}
#else /* !defined(HW_AUDIO) */
static int osd_init_sound(void)
{
return 0;
}
static void osd_stopsound(void)
{
}
static void do_audio_frame()
{
}
void osd_setsound(void (*playfunc)(void *buffer, int length))
{
}
#endif /* !defined(HW_AUDIO) */
/* video */
extern void display_init();
extern void display_write_frame(const uint8_t *data[]);
extern void display_clear();
//This runs on core 0.
QueueHandle_t vidQueue;
static void videoTask(void *arg)
{
bitmap_t *bmp = NULL;
while (1) {
// xQueueReceive(vidQueue, &bmp, portMAX_DELAY); //skip one frame to drop to 30
xQueueReceive(vidQueue, &bmp, portMAX_DELAY);
display_write_frame((const uint8_t **)bmp->line);
}
}
/* get info */
static char fb[1]; //dummy
bitmap_t *myBitmap;
/* initialise video */
static int init(int width, int height)
{
return 0;
}
static void shutdown(void)
{
}
/* set a video mode */
static int set_mode(int width, int height)
{
return 0;
}
/* copy nes palette over to hardware */
uint16 myPalette[256];
static void set_palette(rgb_t *pal)
{
uint16 c;
int i;
for (i = 0; i < 256; i++) {
c = (pal[i].b >> 3) + ((pal[i].g >> 2) << 5) + ((pal[i].r >> 3) << 11);
//myPalette[i]=(c>>8)|((c&0xff)<<8);
myPalette[i] = c;
}
}
/* clear all frames to a particular color */
static void clear(uint8 color)
{
// SDL_FillRect(mySurface, 0, color);
display_clear();
}
/* acquire the directbuffer for writing */
static bitmap_t *lock_write(void)
{
// SDL_LockSurface(mySurface);
myBitmap = bmp_createhw((uint8 *)fb, NES_SCREEN_WIDTH, NES_SCREEN_HEIGHT, NES_SCREEN_WIDTH * 2);
return myBitmap;
}
/* release the resource */
static void free_write(int num_dirties, rect_t *dirty_rects)
{
bmp_destroy(&myBitmap);
}
static void custom_blit(bitmap_t *bmp, int num_dirties, rect_t *dirty_rects)
{
xQueueSend(vidQueue, &bmp, 0);
do_audio_frame();
}
viddriver_t sdlDriver = {
"Simple DirectMedia Layer", /* name */
init, /* init */
shutdown, /* shutdown */
set_mode, /* set_mode */
set_palette, /* set_palette */
clear, /* clear */
lock_write, /* lock_write */
free_write, /* free_write */
custom_blit, /* custom_blit */
false /* invalidate flag */
};
void osd_getvideoinfo(vidinfo_t *info)
{
info->default_width = NES_SCREEN_WIDTH;
info->default_height = NES_SCREEN_HEIGHT;
info->driver = &sdlDriver;
}
void osd_getsoundinfo(sndinfo_t *info)
{
info->sample_rate = DEFAULT_SAMPLERATE;
info->bps = 16;
}
/* input */
extern void controller_init();
extern uint32_t controller_read_input();
static void osd_initinput()
{
controller_init();
}
static void osd_freeinput(void)
{
}
void osd_getinput(void)
{
const int ev[32] = {
event_joypad1_up, event_joypad1_down, event_joypad1_left, event_joypad1_right,
event_joypad1_select, event_joypad1_start, event_joypad1_a, event_joypad1_b,
event_state_save, event_state_load, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0
};
static int oldb = 0xffff;
uint32_t b = controller_read_input();
uint32_t chg = b ^ oldb;
int x;
oldb = b;
event_t evh;
// nofrendo_log_printf("Input: %x\n", b);
for (x = 0; x < 16; x++) {
if (chg & 1) {
evh = event_get(ev[x]);
if (evh)
evh((b & 1) ? INP_STATE_BREAK : INP_STATE_MAKE);
}
chg >>= 1;
b >>= 1;
}
}
void osd_getmouse(int *x, int *y, int *button)
{
}
/* init / shutdown */
static int logprint(const char *string)
{
return printf("%s", string);
}
int osd_init()
{
// nofrendo_log_chain_logfunc(logprint);
if (osd_init_sound())
return -1;
display_init();
vidQueue = xQueueCreate(1, sizeof(bitmap_t *));
xTaskCreatePinnedToCore(&videoTask, "videoTask", 2048, NULL, 0, NULL, 0);
osd_initinput();
return 0;
}
void osd_shutdown()
{
osd_stopsound();
osd_freeinput();
}
char configfilename[] = "na";
int osd_main(int argc, char *argv[])
{
config.filename = configfilename;
return main_loop(argv[0], system_autodetect);
}
//Seemingly, this will be called only once. Should call func with a freq of frequency,
int osd_installtimer(int frequency, void *func, int funcsize, void *counter, int countersize)
{
nofrendo_log_printf("Timer install, configTICK_RATE_HZ=%d, freq=%d\n", configTICK_RATE_HZ, frequency);
timer = xTimerCreate("nes", configTICK_RATE_HZ / frequency, pdTRUE, NULL, func);
xTimerStart(timer, 0);
return 0;
}
/* filename manipulation */
void osd_fullname(char *fullname, const char *shortname)
{
strncpy(fullname, shortname, PATH_MAX);
}
/* This gives filenames for storage of saves */
char *osd_newextension(char *string, char *ext)
{
// dirty: assume both extensions is 3 characters
size_t l = strlen(string);
string[l - 3] = ext[1];
string[l - 2] = ext[2];
string[l - 1] = ext[3];
return string;
}
/* This gives filenames for storage of PCX snapshots */
int osd_makesnapname(char *filename, int len)
{
return -1;
}

51
example/nes/pin_config.h Normal file
View File

@ -0,0 +1,51 @@
#pragma once
// #define HW_CONTROLLER_GPIO
// #define HW_CONTROLLER_GPIO_ANALOG_JOYSTICK
#define HW_CONTROLLER_DABBLE_APP
/*ESP32S3*/
#define PIN_LCD_BL 38
#define PIN_LCD_D0 39
#define PIN_LCD_D1 40
#define PIN_LCD_D2 41
#define PIN_LCD_D3 42
#define PIN_LCD_D4 45
#define PIN_LCD_D5 46
#define PIN_LCD_D6 47
#define PIN_LCD_D7 48
#define PIN_POWER_ON 15
#define PIN_LCD_RES 5
#define PIN_LCD_CS 6
#define PIN_LCD_DC 7
#define PIN_LCD_WR 8
#define PIN_LCD_RD 9
#define PIN_BUTTON_1 0
#define PIN_BUTTON_2 14
#define PIN_BAT_VOLT 4
#define PIN_IIC_SCL 17
#define PIN_IIC_SDA 18
#define PIN_TOUCH_INT 16
#define PIN_TOUCH_RES 21
/* nes controller gpio */
#define HW_CONTROLLER_GPIO_UP_DOWN
#define HW_CONTROLLER_GPIO_LEFT_RIGHT
#define HW_CONTROLLER_GPIO_UP
#define HW_CONTROLLER_GPIO_DOWN
#define HW_CONTROLLER_GPIO_LEFT
#define HW_CONTROLLER_GPIO_RIGHT
#define HW_CONTROLLER_GPIO_SELECT
#define HW_CONTROLLER_GPIO_START
#define HW_CONTROLLER_GPIO_A
#define HW_CONTROLLER_GPIO_B
#define HW_CONTROLLER_GPIO_X
#define HW_CONTROLLER_GPIO_Y

View File

@ -0,0 +1,32 @@
; PlatformIO Project Configuration File
;
; Build options: build flags, source filter
; Upload options: custom upload port, speed and extra flags
; Library options: dependencies, extra library storages
; Advanced options: extra scripting
;
; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html
[platformio]
globallib_dir = ../../lib
src_dir = .
[env:ESP32-S3-DevKitC-1]
platform = espressif32
board = esp32-s3-devkitc-1
framework = arduino
platform_packages =
framework-arduinoespressif32@https://github.com/espressif/arduino-esp32.git#2.0.5
build_flags =
-DLV_LVGL_H_INCLUDE_SIMPLE
-DBOARD_HAS_PSRAM
-DARDUINO_USB_MODE=1
; The need to print data using USB is uncommented
-DARDUINO_USB_CDC_ON_BOOT=1
board_build.arduino.memory_type = qio_opi

165
lib/DabbleESP32/LICENSE Normal file
View File

@ -0,0 +1,165 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.
0. Additional Definitions.
As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.
"The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.
An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
A "Combined Work" is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".
The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
a) under this License, provided that you make a good faith effort to
ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
b) under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from
a header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
a) Give prominent notice with each copy of the object code that the
Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the object code with a copy of the GNU GPL and this license
document.
4. Combined Works.
You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:
a) Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the Combined Work with a copy of the GNU GPL and this license
document.
c) For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
d) Do one of the following:
0) Convey the Minimal Corresponding Source under the terms of this
License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
1) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (a) uses at run time
a copy of the Library already present on the user's computer
system, and (b) will operate properly with a modified version
of the Library that is interface-compatible with the Linked
Version.
e) Provide Installation Information, but only if you would otherwise
be required to provide such information under section 6 of the
GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the
Application with a modified version of the Linked Version. (If
you use option 4d0, the Installation Information must accompany
the Minimal Corresponding Source and Corresponding Application
Code. If you use option 4d1, you must provide the Installation
Information in the manner specified by section 6 of the GNU GPL
for conveying Corresponding Source.)
5. Combined Libraries.
You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
a) Accompany the combined library with a copy of the same work based
on the Library, uncombined with any other library facilities,
conveyed under the terms of this License.
b) Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.

18
lib/DabbleESP32/README.md Normal file
View File

@ -0,0 +1,18 @@
Whether youre a student, a teacher, or a hobbyist, Dabble is the perfect place for all your DIYing needs. It transforms your Smartphone into a virtual I/O device and lets you control hardware via Bluetooth, communicate with it, access sensors like accelerometer, GPS, proximity and other features of your Smartphone. It also provides you with dedicated projects compatible with Scratch and Arduino to help you learn by doing. Currently Dabble is avaiable for Android users(coming soon for iPhone users) and its is supported on Android version 5.0.0 and above. One can download the app from Google PlayStore with this link given below. [https://play.google.com/store/apps/details?id=io.dabbleapp]
The app is designed to provide data of certain features of your smartphone to evive and microcontroller boards like Arduino Uno, Nano and Mega and ESP32.It also allows you to control them by your Smartphone. The app communicates with these boards via bluetooth modules like HC-05, HC-06 and HM-10 in case of Arduino boards and with built-in bluetooth for ESP32. This repository consists of library required on your board side for communication with app using BLE on ESP32. Dabble consists of various modules that allows you to control your hardware and access various smartphone features. A brief description of each module is mentioned below:
1) Led Brightness Control: This module allows you to control digital pin of your hardware through mobile. You can make pins HIGH or LOW, can also change its PWM if PWM functionailty is supported on that pin. You can use this module to control LED brightness and carry other such activities.
2) Terminal: Send and receive text and voice commands over Bluetooth between your hardware and smartphone.
3) Gamepad: Control devices in analog (Joystick), digital, and accelerometer mode.
4) Pin State Monitor: Remotely monitor the live status of devices and debug them.
5) Motor Control: Control actuators such as the DC motor and servo motor.
6) Inputs: Provide analog and digital inputs via buttons, knobs, and switches.
7) Camera: Use the camera of your Smartphone for taking photos and videos and colour detection.
8) Phone Sensor: Access different sensors of your Smartphone such as the accelerometer, gyroscope, proximity sensor,magnetometer, light meter, sound meter, GPS, temperature sensor, and barometer to make projects and conduct experiments.
9) Oscilloscope: Visualise and analyse the input and output signals given to the device using the oscilloscope module.
10) IoT: This module consist of Data Logger Module. Module to publish and fetch data will be available soon.
11) Music: Receive commands from the device and play tones, songs, or other recorded files on your Smartphone.
12) Projects: Make dedicated projects to experience different concepts of the real world first-hand.
Dabble Library
As per the module set present in Dabble app the library is also structured in same way. This library is for ESP32. It consists of certain examples codes which will help you in getting started with various Dabble modules. To explore more about Dabble, goto [https://thestempedia.com/docs/dabble/getting-started-with-dabble/]

View File

@ -0,0 +1,35 @@
/*
This is Led brightness control example for ESP32 that uses LED Brightness Control Module in Dabble app.
This module allows you to control state of pin. You can make pin HIGH or LOW or can also assign any PWM
value to it.
NOTE: As in esp32 any channel can be configured as a PWM channel hence any first eight pins controlled by Module
will be treated as PWM and others will be treated as normal digital pins.
You can reduce the size of library compiled by enabling only those modules that you want to
use.For this first define CUSTOM_SETTINGS followed by defining INCLUDE_modulename.
Explore more on: https://thestempedia.com/docs/dabble/getting-started-with-dabble/
*/
#define CUSTOM_SETTINGS
#define INCLUDE_LEDCONTROL_MODULE
#include <DabbleESP32.h>
unsigned long lasttime=0;
void setup() {
Serial.begin(115200); // make sure your Serial Monitor is also set at this baud rate.
Dabble.begin("MyEsp32"); //set bluetooth name of your device
}
void loop() {
Dabble.processInput(); //this function is used to refresh data obtained from smartphone.Hence calling this function is mandatory in order to get data properly from your mobile.
//uncomment if you want to check if paramters read correctly
/*Serial.print("Led:");
Serial.print(LedControl.getpinNumber());
Serial.print('\t');
Serial.print("State:"); //0 if led is Off. 1 if led is On.
Serial.print(LedControl.getpinState());
Serial.print('\t');
Serial.print("Brightness:");
Serial.println(LedControl.readBrightness());*/
}

View File

@ -0,0 +1,44 @@
/*
Terminal Module is like a chat box. It allows you to send and receive commands between your
board and smartphone.
You can reduce the size of library compiled by enabling only those modules that you
want to use. For this first define CUSTOM_SETTINGS followed by defining
INCLUDE_modulename.
Explore more on: https://thestempedia.com/docs/dabble/terminal-module/
*/
#define CUSTOM_SETTINGS
#define INCLUDE_TERMINAL_MODULE
#include <DabbleESP32.h>
String Serialdata = "";
bool dataflag = 0;
void setup() {
Serial.begin(115200); // make sure your Serial Monitor is also set at this baud rate.
Dabble.begin("MyEsp32"); //set bluetooth name of your device
}
void loop() {
Dabble.processInput(); //this function is used to refresh data obtained from smartphone.Hence calling this function is mandatory in order to get data properly from your mobile.
while (Serial.available() != 0)
{
Serialdata = String(Serialdata + char(Serial.read()));
dataflag = 1;
}
if (dataflag == 1)
{
Terminal.print(Serialdata);
Serialdata = "";
dataflag = 0;
}
if (Terminal.available() != 0)
{
while (Terminal.available() != 0)
{
Serial.write(Terminal.read());
}
Serial.println();
}
}

View File

@ -0,0 +1,88 @@
/*
Gamepad module provides three different mode namely Digital, JoyStick and Accerleometer.
You can reduce the size of library compiled by enabling only those modules that you want to
use. For this first define CUSTOM_SETTINGS followed by defining INCLUDE_modulename.
Explore more on: https://thestempedia.com/docs/dabble/game-pad-module/
*/
#define CUSTOM_SETTINGS
#define INCLUDE_GAMEPAD_MODULE
#include <DabbleESP32.h>
void setup() {
// put your setup code here, to run once:
Serial.begin(115200); // make sure your Serial Monitor is also set at this baud rate.
Dabble.begin("MyEsp32"); //set bluetooth name of your device
}
void loop() {
Dabble.processInput(); //this function is used to refresh data obtained from smartphone.Hence calling this function is mandatory in order to get data properly from your mobile.
Serial.print("KeyPressed: ");
if (GamePad.isUpPressed())
{
Serial.print("Up");
}
if (GamePad.isDownPressed())
{
Serial.print("Down");
}
if (GamePad.isLeftPressed())
{
Serial.print("Left");
}
if (GamePad.isRightPressed())
{
Serial.print("Right");
}
if (GamePad.isSquarePressed())
{
Serial.print("Square");
}
if (GamePad.isCirclePressed())
{
Serial.print("Circle");
}
if (GamePad.isCrossPressed())
{
Serial.print("Cross");
}
if (GamePad.isTrianglePressed())
{
Serial.print("Triangle");
}
if (GamePad.isStartPressed())
{
Serial.print("Start");
}
if (GamePad.isSelectPressed())
{
Serial.print("Select");
}
Serial.print('\t');
int a = GamePad.getAngle();
Serial.print("Angle: ");
Serial.print(a);
Serial.print('\t');
int b = GamePad.getRadius();
Serial.print("Radius: ");
Serial.print(b);
Serial.print('\t');
float c = GamePad.getXaxisData();
Serial.print("x_axis: ");
Serial.print(c);
Serial.print('\t');
float d = GamePad.getYaxisData();
Serial.print("y_axis: ");
Serial.println(d);
Serial.println();
}

View File

@ -0,0 +1,36 @@
/*
Pin State Monitor is made for monitoring status of analog and digital pins of your board.
In this example bluetooth is to be connected on HardwareSerial0 for Uno and Nano Boards.
NOTE: State for only following pins can be seen on Pin State Monitor:
| Screen Name | GPIO Pins |
| Digital | 2,4,5,12,13,14,15,16,17,18,19,21 |
| | 23,25,26,27 |
| Analog | 32,33,34,35,36,39 |
You can reduce the size of library compiled by enabling only those modules that you want
to use. For this first define CUSTOM_SETTINGS followed by defining INCLUDE_modulename.
Explore more on: https://thestempedia.com/docs/dabble/pin-state-monitor-module/
*/
#define CUSTOM_SETTINGS
#define INCLUDE_PINMONITOR_MODULE
#include <DabbleESP32.h>
void setup() {
/*
NOTE: PinMonitor only displays status of the pins of your board. It does not configure pinMode of the pins.
So if there is any necessity to define pinMode then declare it setup as per requirement.
*/
Serial.begin(115200); // make sure your Serial Monitor is also set at this baud rate.
Dabble.begin("MyEsp32"); //set bluetooth name of your device
}
void loop() {
Dabble.processInput(); //this function is used to refresh data obtained from smartphone.Hence calling this function is mandatory in order to get data properly from your mobile.
PinMonitor.sendDigitalData();
PinMonitor.sendAnalogData();
delayMicroseconds(20);
}

View File

@ -0,0 +1,40 @@
/*
MotorControl Module is used to control actuators like DC motors and Servos.
NOTE: If you are interested in using any other pin as PWM pin then use led channels
from channel 4 onwards on ESP32.Because first four channels are for controlling motor and servo from
Motor control module of Dabble.
You can reduce the size of library compiled by enabling only those modules that you want to
use. For this first define CUSTOM_SETTINGS followed by defining INCLUDE_modulename.
Explore more on: https://thestempedia.com/docs/dabble/motor-control-module/
*/
#define CUSTOM_SETTINGS
#define INCLUDE_MOTORCONTROL_MODULE
#include <DabbleESP32.h>
uint8_t pinServo1 = 4;
uint8_t pinServo2 = 5;
uint8_t pwmMotor1 = 12;
uint8_t dir1Motor1 = 13;
uint8_t dir2Motor1 = 14;
uint8_t pwmMotor2 = 21;
uint8_t dir1Motor2 = 22;
uint8_t dir2Motor2 = 23;
void setup() {
Serial.begin(115200); // make sure your Serial Monitor is also set at this baud rate.
Dabble.begin("MyEsp32"); //set bluetooth name of your device
}
void loop() {
Dabble.processInput(); //this function is used to refresh data obtained from smartphone.Hence calling this function is mandatory in order to get data properly from your mobile. //this function is used to refresh data obtained from smartphone.Hence calling this function is mandatory in order to get data properly from your mobile.
Controls.runServo1(pinServo1);
Controls.runServo2(pinServo2);
Controls.runMotor1(pwmMotor1,dir1Motor1,dir2Motor1);
Controls.runMotor2(pwmMotor2,dir1Motor2,dir2Motor2);
}

View File

@ -0,0 +1,38 @@
/*
DabbleInputs module of your smartphone consists of two potentiometers, two slideswitches and two push button.
You can reduce the size of library compiled by enabling only those modules that you want to
use. For this first define CUSTOM_SETTINGS followed by defining INCLUDE_modulename.
Explore more on: https://thestempedia.com/docs/dabble/input-module/
*/
#define CUSTOM_SETTINGS
#define INCLUDE_DABBLEINPUTS_MODULE
#include <DabbleESP32.h>
void setup() {
Serial.begin(115200); // make sure your Serial Monitor is also set at this baud rate.
Dabble.begin("MyEsp32"); //set bluetooth name of your device
}
void loop() {
Dabble.processInput(); //this function is used to refresh data obtained from smartphone.Hence calling this function is mandatory in order to get data properly from your mobile.
Serial.print("Pot1:");
Serial.print(Inputs.getPot1Value());
Serial.print('\t');
Serial.print("Pot2:");
Serial.print(Inputs.getPot2Value());
Serial.print('\t');
Serial.print("SS1:");
Serial.print(Inputs.getSlideSwitch1Value());
Serial.print('\t');
Serial.print("SS2:");
Serial.print(Inputs.getSlideSwitch2Value());
Serial.print('\t');
Serial.print("TS1:");
Serial.print(Inputs.getTactileSwitch1Value());
Serial.print('\t');
Serial.print("TS2:");
Serial.print(Inputs.getTactileSwitch2Value());
Serial.println();
}

View File

@ -0,0 +1,69 @@
/*
Camera Module allows you to click images and take videos from smartphone by sending commands from your hardware.
This function demonstrates functions available in library for camera module.
Open Serial monitor and follow the instructions printed there to take images and videos in different cases.
You can reduce the size of library compiled by enabling only those modules that you want
to use. For this first define CUSTOM_SETTINGS followed by defining INCLUDE_modulename.
Explore more on: https://thestempedia.com/docs/dabble/camera-module-photos-videos/
*/
#define CUSTOM_SETTINGS
#define INCLUDE_CAMERA_MODULE
#include <DabbleESP32.h>
void setup() {
Serial.begin(115200); // make sure your Serial Monitor is also set at this baud rate.
Dabble.begin("MyEsp32"); //set bluetooth name of your device
printMessage();
}
void loop() {
//upload code and open serial monitor (reset your board once if you cannot see any message printed on Serial Monitor)
Dabble.processInput(); //this function is used to refresh data obtained from smartphone.Hence calling this function is mandatory in order to get data properly from your mobile.
char a = processSerialdata();
if( a == '1')
{
Camera.setParameters(FRONT,OFF,HIGH_QUALITY,0); //Camera Direction, Flash, quality, Zoom(from 0 to 100%)
Camera.captureImage();
}
if( a == '2')
{
Camera.flipTo(REAR);
Camera.flashMode(OFF);
Camera.setQuality(LOW_QUALITY);
Camera.captureImage();
}
if(a == '3')
{
Camera.flipTo(REAR);
Camera.setQuality(HIGH_QUALITY);
Camera.zoom(50);
Camera.captureImage();
}
}
void printMessage()
{
Serial.println("Enter any number between 1 to 3 for executing task corresponding to that number: ");
Serial.println("Tasks executed on sending different numbers are as followed: ");
Serial.println("1 - Take a high quality image from front camera with no flash and no zoom.");
Serial.println("2 - Take a low quality image from rear camera with Off flash and no zoom");
Serial.println("3 - Take a 50% zoomed image from Rear camera with high quality");
}
char processSerialdata()
{
if(Serial.available()!=0)
{
return Serial.read();
}
else
{
return '0';
}
}

View File

@ -0,0 +1,74 @@
/*
Camera Module allows you to click images and videos from smartphone by sending commands from your board.
This function demonstrates functions available in library for camera module.
Open Serial monitor and follow the instructions printed there to take videos in different settings of camera.
You can reduce the size of library compiled by enabling only those modules that you want
to use. For this first define CUSTOM_SETTINGS followed by defining INCLUDE_modulename.
Explore more on: https://thestempedia.com/docs/dabble/camera-module-photos-videos/
*/
#define CUSTOM_SETTINGS
#define INCLUDE_CAMERA_MODULE
#include <DabbleESP32.h>
void setup() {
Serial.begin(115200); // make sure your Serial Monitor is also set at this baud rate.
Dabble.begin("MyEsp32"); //set bluetooth name of your device
printMessage();
}
void loop() {
//upload code and open serial monitor (reset your board if you cannot se any message printed on Serial Monitor)
Dabble.processInput(); //this function is used to refresh data obtained from smartphone.Hence calling this function is mandatory in order to get data properly from your mobile.
char a = processSerialdata();
if( a == '1')
{
Camera.setParameters(FRONT,OFF,HIGH_QUALITY,0); //Direction , Flash, Quality, zoom(0-100%)
Camera.startRecording();
}
if( a == '2')
{
Camera.flipTo(REAR);
Camera.flashMode(AUTO);
Camera.setQuality(LOW_QUALITY);
Camera.startRecording();
}
if(a == '3')
{
Camera.flipTo(REAR);
Camera.setQuality(HIGH_QUALITY);
Camera.zoom(50);
Camera.startRecording();
}
if(a == '4')
{
Camera.stopRecording();
}
}
void printMessage()
{
Serial.println("Enter any number between 1 to 4 for executing task corresponding to that number: ");
Serial.println("Tasks executed on sending different numbers are as followed: ");
Serial.println("1 - Take a high quality video from front camera with no flash and no zoom.");
Serial.println("2 - Take a low quality video from rear camera with Auto flash");
Serial.println("3 - Take a 50% zoomed image from Rear camera with high quality");
Serial.println("4 - Stop video recording");
}
char processSerialdata()
{
if(Serial.available()!=0)
{
return Serial.read();
}
else
{
return '0';
}
}

View File

@ -0,0 +1,35 @@
/*
Accelerometer block of Phone sensor module allows you to access your smartphone's accelerometer values.
You can reduce the size of library compiled by enabling only those modules that you wan to
use. For this first define CUSTOM_SETTINGS followed by defining INCLUDE_modulename.
Explore more on: https://thestempedia.com/docs/dabble/phone-sensors-module/
*/
#define CUSTOM_SETTINGS
#define INCLUDE_SENSOR_MODULE
#include <DabbleESP32.h>
void setup() {
Serial.begin(115200); // make sure your Serial Monitor is also set at this baud rate.
Dabble.begin("MyEsp32"); //set bluetooth name of your device
}
void loop() {
Dabble.processInput(); //this function is used to refresh data obtained from smartphone.Hence calling this function is mandatory in order to get data properly from your mobile.
print_Accelerometer_data();
}
void print_Accelerometer_data()
{
Serial.print("X_axis: ");
Serial.print(Sensor.getAccelerometerXaxis(), 4);
Serial.print('\t');
Serial.print("Y_axis: ");
Serial.print(Sensor.getAccelerometerYaxis(), 4);
Serial.print('\t');
Serial.print("Z_axis: ");
Serial.println(Sensor.getAccelerometerZaxis(), 4);
Serial.println();
}

View File

@ -0,0 +1,29 @@
/*
If your smartphone has Barometer sensor support then this code helps in accessing that sensor's value through Dabble app.
You can reduce the size of library compiled by enabling only those modules that you want to
use. For this first define CUSTOM_SETTINGS followed by defining INCLUDE_modulename.
Explore more on: https://thestempedia.com/docs/dabble/phone-sensors-module/
*/
#define CUSTOM_SETTINGS
#define INCLUDE_SENSOR_MODULE
#include <DabbleESP32.h>
void setup() {
Serial.begin(115200); // make sure your Serial Monitor is also set at this baud rate.
Dabble.begin("MyEsp32"); //set bluetooth name of your device
}
void loop() {
Dabble.processInput(); //this function is used to refresh data obtained from smartphone.Hence calling this function is mandatory in order to get data properly from your mobile.
print_Barometer_data();
}
void print_Barometer_data()
{
Serial.print("Barometer: ");
Serial.println(Sensor.getBarometerPressure(), 7);
Serial.println();
}

View File

@ -0,0 +1,34 @@
/*
This module helps you in accessing GPS values of our smartphone.
You can reduce the size of library compiled by enabling only those modules that you want
to use. For this first define CUSTOM_SETTINGS followed by defining INCLUDE_modulename.
Explore more on: https://thestempedia.com/docs/dabble/phone-sensors-module/
*/
#define CUSTOM_SETTINGS
#define INCLUDE_SENSOR_MODULE
#include <DabbleESP32.h>
void setup() {
Serial.begin(115200); // make sure your Serial Monitor is also set at this baud rate.
Dabble.begin("MyEsp32"); //set bluetooth name of your device
}
void loop() {
Dabble.processInput(); //this function is used to refresh data obtained from smartphone.Hence calling this function is mandatory in order to get data properly from your mobile.
print_GPS_data();
}
void print_GPS_data()
{
Serial.print("Longitude: ");
Serial.print(Sensor.getGPSlongitude(), 7);
Serial.print('\t');
Serial.print('\t');
Serial.print("Latitude: ");
Serial.println(Sensor.getGPSLatitude(), 7);
Serial.println();
}

View File

@ -0,0 +1,37 @@
/*
With this block of phone sensor module you can access gyroscope values of your smartphone.
Gyroscope gives you angular acceleration in x,y and z axis.
You can reduce the size of library compiled by enabling only those modules that you want
to use. For this first define CUSTOM_SETTINGS followed by defining
INCLUDE_modulename.
Explore more on: https://thestempedia.com/docs/dabble/phone-sensors-module/
*/
#define CUSTOM_SETTINGS
#define INCLUDE_SENSOR_MODULE
#include <DabbleESP32.h>
void setup() {
Serial.begin(115200); // make sure your Serial Monitor is also set at this baud rate.
Dabble.begin("MyEsp32"); //set bluetooth name of your device
}
void loop() {
Dabble.processInput(); //this function is used to refresh data obtained from smartphone.Hence calling this function is mandatory in order to get data properly from your mobile.
print_Gyroscope_data();
}
void print_Gyroscope_data()
{
Serial.print("X-axis: ");
Serial.print(Sensor.getGyroscopeXaxis());
Serial.print('\t');
Serial.print("Y-axis: ");
Serial.print(Sensor.getGyroscopeYaxis());
Serial.print('\t');
Serial.print("Z-axis: ");
Serial.println(Sensor.getGyroscopeZaxis());
Serial.println();
}

View File

@ -0,0 +1,29 @@
/*
This block gives light intensity sensed by smartphone.
You can reduce the size of library compiled by enabling only those modules that you want to
use. For this first define CUSTOM_SETTINGS followed by defining INCLUDE_modulename.
Explore more on: https://thestempedia.com/docs/dabble/phone-sensors-module/
*/
#define CUSTOM_SETTINGS
#define INCLUDE_SENSOR_MODULE
#include <DabbleESP32.h>
void setup() {
Serial.begin(115200); // make sure your Serial Monitor is also set at this baud rate.
Dabble.begin("MyEsp32"); //set bluetooth name of your device
}
void loop() {
Dabble.processInput(); //this function is used to refresh data obtained from smartphone.Hence calling this function is mandatory in order to get data properly from your mobile.
print_Light_data();
}
void print_Light_data()
{
Serial.print("LIGHT: ");
Serial.println(Sensor.getLightIntensity(), 7);
Serial.println();
}

View File

@ -0,0 +1,35 @@
/*
Magnetometer block helps in accessing your mobile's magnetometer.
You can reduce the size of library compiled by enabling only those modules that you want
to use. For this first define CUSTOM_SETTINGS followed by defining INCLUDE_modulename.
Explore more on: https://thestempedia.com/docs/dabble/phone-sensors-module/
*/
#define CUSTOM_SETTINGS
#define INCLUDE_SENSOR_MODULE
#include <DabbleESP32.h>
void setup() {
Serial.begin(115200); // make sure your Serial Monitor is also set at this baud rate.
Dabble.begin("MyEsp32"); //set bluetooth name of your device
}
void loop() {
Dabble.processInput(); //this function is used to refresh data obtained from smartphone.Hence calling this function is mandatory in order to get data properly from your mobile.
print_Magnetometer_data();
}
void print_Magnetometer_data()
{
Serial.print("X-axis: ");
Serial.print(Sensor.getMagnetometerXaxis(), 7);
Serial.print('\t');
Serial.print("Y-axis: ");
Serial.print(Sensor.getMagnetometerYaxis(), 7);
Serial.print('\t');
Serial.print("Z-axis: ");
Serial.println(Sensor.getMagnetometerZaxis(), 7);
Serial.println();
}

View File

@ -0,0 +1,31 @@
/*
Proximity block allows to access proximity sensor of your mobile. This sensor in mobile
phone gives two different values depending on the fact is object is near or far. You will get
0 reading when object is very close to phone and any random number if object is far.
You can reduce the size of library compiled by enabling only those modules that you want
to use. For this first define CUSTOM_SETTINGS followed by defining INCLUDE_modulename.
Explore more on: https://thestempedia.com/docs/dabble/phone-sensors-module/
*/
#define CUSTOM_SETTINGS
#define INCLUDE_SENSOR_MODULE
#include <DabbleESP32.h>
void setup() {
Serial.begin(115200); // make sure your Serial Monitor is also set at this baud rate.
Dabble.begin("MyEsp32"); ////set bluetooth name of your device
}
void loop() {
Dabble.processInput(); //this function is used to refresh data obtained from smartphone.Hence calling this function is mandatory in order to get data properly from your mobile.
print_Proximity_data();
}
void print_Proximity_data()
{
Serial.print("Distance: ");
Serial.println(Sensor.getProximityDistance(), 7);
Serial.println();
}

View File

@ -0,0 +1,28 @@
/*
Sound sensor gives decibal value of sound that is sensed by your mobile's microphone.
You can reduce the size of library compiled by enabling only those modules that you want
to use. For this first define CUSTOM_SETTINGS followed by defining INCLUDE_modulename.
Explore more on: https://thestempedia.com/docs/dabble/phone-sensors-module/
*/
#define CUSTOM_SETTINGS
#define INCLUDE_SENSOR_MODULE
#include <DabbleESP32.h>
void setup() {
Serial.begin(115200); // make sure your Serial Monitor is also set at this baud rate.
Dabble.begin("Myesp32"); //set bluetooth name of your device
}
void loop() {
Dabble.processInput(); //this function is used to refresh data obtained from smartphone.Hence calling this function is mandatory in order to get data properly from your mobile.
print_Sound_data();
}
void print_Sound_data()
{
Serial.print("SOUND: ");
Serial.println(Sensor.getSoundDecibels(), 3);
Serial.println();
}

View File

@ -0,0 +1,29 @@
/*
If there is temperature sensor in your smartphone then you can access it through this example.
You can reduce the size of library compiled by enabling only those modules that you want
to use. For this first define CUSTOM_SETTINGS followed by defining INCLUDE_modulename.
Explore more on: https://thestempedia.com/docs/dabble/phone-sensors-module/
*/
#define CUSTOM_SETTINGS
#define INCLUDE_SENSOR_MODULE
#include <DabbleESP32.h>
void setup() {
Serial.begin(115200); // make sure your Serial Monitor is also set at this baud rate.
Dabble.begin("MyEsp32"); //Enter baudrate of your bluetooth.Connect bluetooth on Bluetooth port present on evive.
}
void loop() {
Dabble.processInput(); //this function is used to refresh data obtained from smartphone.Hence calling this function is mandatory in order to get data properly from your mobile.
print_Temperature_data();
}
void print_Temperature_data()
{
Serial.print("TEMPERATURE: ");
Serial.println(Sensor.getTemperature(), 7);
Serial.println();
}

View File

@ -0,0 +1,49 @@
/*
Data Logger module helps you in storing data in form of .csv file.
Later you can open this file to view your stored data.
You can reduce the size of library compiled by enabling only those modules that you want to
use.For this first define CUSTOM_SETTINGS followed by defining INCLUDE_modulename.
Explore more on: https://thestempedia.com/docs/dabble/
*/
#define CUSTOM_SETTINGS
#define INCLUDE_SENSOR_MODULE
#define INCLUDE_DATALOGGER_MODULE
#include <DabbleESP32.h>
bool isFileOpen = true;
uint8_t closeFileSignalPin = 2; //this pin is internally pulled up and a push button grounded on one side is connected to pin so that pin detects low logic when push button is pressed.
void initializeFile(){
Serial.println("Initialize");
DataLogger.createFile("Microphone");
DataLogger.createColumn("Decibel");
}
void setup() {
pinMode(closeFileSignalPin,INPUT_PULLUP);
Serial.begin(115200); // make sure your Serial Monitor is also set at this baud rate.
Dabble.begin("Myesp32"); //set bluetooth name of your device
DataLogger.sendSettings(&initializeFile);
}
void loop() {
Dabble.processInput(); //this function is used to refresh data obtained from smartphone.Hence calling this function is mandatory in order to get data properly from your mobile.
if( isFileOpen == true)
{
print_Sound_data();
DataLogger.send("Decibel",Sensor.getdata_Sound());
}
if((digitalRead(closeFileSignalPin) == LOW) && isFileOpen == true)
{
isFileOpen = false;
DataLogger.stop();
}
}
void print_Sound_data()
{
Serial.print("SOUND: ");
Serial.println(Sensor.getdata_Sound(), 3);
Serial.println();
}

View File

@ -0,0 +1,35 @@
/*
Notification module can be used for notifying your mobile about status of various activities happening on your hardware.
In this example a push button is connected to a digital pin. And mobile is notified about how many times that push button
is pressed.
You can reduce the size of library compiled by enabling only those modules that you want to
use. For this first define CUSTOM_SETTINGS followed by defining INCLUDE_modulename.
Explore more on: https://thestempedia.com/docs/dabble/
*/
#define CUSTOM_SETTINGS
#define INCLUDE_NOTIFICATION_MODULE
#include <DabbleESP32.h>
uint8_t pushButtonPin = 2;
int counts = 0;
void setup() {
Serial.begin(115200);
Dabble.begin("MyEsp32"); //set bluetooth name of your device
pinMode(pushButtonPin, INPUT_PULLUP); //Since pin is internally pulled up hence connect one side of push button to ground so whenever button is pushed pin reads LOW logic.
Dabble.waitForAppConnection(); //waiting for App to connect
Notification.clear(); //clear previous notifictions
Notification.setTitle("Button Counts"); //Enter title of your notification
}
void loop() {
Dabble.processInput(); //this function is used to refresh data obtained from smartphone.Hence calling this function is mandatory in order to get data properly from your mobile.
if (digitalRead(pushButtonPin) == LOW)
{
counts++;
delay(1000); //debounce delay
}
Notification.notifyPhone(String("Button has been pressed ") + counts + String (" time"));
}

View File

@ -0,0 +1,28 @@
/*
SMS module uses your smartphone to send SMS based on events occuring in your hardware board.
You can reduce the size of library compiled by enabling only those modules that you want to
use. For this first define CUSTOM_SETTINGS followed by defining INCLUDE_modulename.
Explore more on: https://thestempedia.com/docs/dabble/
*/
#define CUSTOM_SETTINGS
#define INCLUDE_SMS_MODULE
#include <DabbleESP32.h>
uint8_t pushButtonPin = 2;
void setup() {
Dabble.begin("MyEsp32"); //set bluetooth name of your device
pinMode(pushButtonPin, INPUT_PULLUP); //Since pin is internally pulled up hence connect one side of push button to ground so whenever button is pushed pin reads LOW logic.
}
void loop() {
Dabble.processInput(); //this function is used to refresh data obtained from smartphone.Hence calling this function is mandatory in order to get data properly from your mobile.
if(digitalRead(pushButtonPin) == LOW)
{
SMS.sendMessage("0123456789","Buenas Noches"); //Contact Number, message content
delay(1000); //debounce delay
}
}

View File

@ -0,0 +1,57 @@
/*
This code demonstrates how to use music module. Here a push button is used for playing and stopping music in smartphone.
A push button is connected on an internally pulled up digital pin. And a change in state of pin is read.
With every press on push button state of music module will be toggled.If no music is played by music module then
command to play music module will be sent and if currently music is being played then it will be stopped.
You can reduce the size of library compiled by enabling only those modules that you want to
use. For this first define CUSTOM_SETTINGS followed by defining INCLUDE_modulename.
Explore more on: https://thestempedia.com/docs/dabble/
*/
#define CUSTOM_SETTINGS
#define INCLUDE_MUSIC_MODULE
#include <DabbleESP32.h>
bool playMusic = false;
uint8_t musicSignalPin = 2;
bool currentStatusOfPin = 0, prevStatusOfPin = 0; //status of musicSignalPin
bool musicIsOn = false;
void setup() {
pinMode(musicSignalPin, INPUT_PULLUP);
Dabble.begin("MyEsp32"); //set bluetooth name of your device
}
void loop() {
Dabble.processInput(); //this function is used to refresh data obtained from smartphone.Hence calling this function is mandatory in order to get data properly from your mobile.
currentStatusOfPin = digitalRead(musicSignalPin);
if (currentStatusOfPin == 0 && prevStatusOfPin == 1) //detecting change in state of pin due to push button
{
delay(500); // debouncedelay
playMusic = !(playMusic);
}
if (playMusic == true)
{
if (musicIsOn == false)
{
Music.play("A4"); //assigned key for Piano Note A4
Music.addToQueue("B4"); //assigned key for Piano Note B4
Music.addToQueue("C4"); //assigned key for Piano Note C4
Music.addToQueue("D4"); //assigned key for Piano Note D4
Music.addToQueue("E4"); //assigned key for Piano Note E4
Music.addToQueue("F4"); //assigned key for Piano Note F4
Music.addToQueue("G4"); //assigned key for Piano Note G4
Music.addToQueue("C5"); //assigned key for Piano Note C5 //Select your own music files, assign them key and write this key as written here for various piano notes.
musicIsOn = true;
}
}
if (playMusic == false)
{
Music.stop();
musicIsOn = false;
}
prevStatusOfPin = currentStatusOfPin;
}

View File

@ -0,0 +1,178 @@
#######################################
# Syntax Coloring Map For Dabble
#######################################
#######################################
# Datatypes (KEYWORD1)
#######################################
DabbleESP32 KEYWORD1
Dabble KEYWORD1
LedControl KEYWORD1
GamePad KEYWORD1
Inputs KEYWORD1
Terminal KEYWORD1
PinMonitor KEYWORD1
Internet KEYWORD1
Sensor KEYWORD1
IOT KEYWORD1
Camera KEYWORD1
ColorDetector KEYWORD1
DataLogger KEYWORD1
Controls KEYWORD1
#######################################
# Functions (KEYWORD2)
#######################################
readBrightness KEYWORD2
getpinState KEYWORD2
getpinNumber KEYWORD2
getx_axis KEYWORD2
gety_axis KEYWORD2
getAngle KEYWORD2
getRadius KEYWORD2
isStartPressed KEYWORD2
isSelectPressed KEYWORD2
isCirclePressed KEYWORD2
isCrossPressed KEYWORD2
isSquarePressed KEYWORD2
isTrianglePressed KEYWORD2
isLeftPressed KEYWORD2
isRightPressed KEYWORD2
isUpPressed KEYWORD2
isDownPressed KEYWORD2
defineServopins KEYWORD2
motorControls KEYWORD2
getpwm_Motor1 KEYWORD2
getpwm_Motor2 KEYWORD2
runMotor1 KEYWORD2
runMotor2 KEYWORD2
runServo1 KEYWORD2
runServo2 KEYWORD2
sendpinsStatus KEYWORD2
sendanalogData KEYWORD2
sendDigitalData KEYWORD2
sendAnalogData KEYWORD2
getvalue_Pot1 KEYWORD2
getvalue_Pot2 KEYWORD2
getStatus_SlideSwitch1 KEYWORD2
getStatus_SlideSwitch2 KEYWORD2
getStatus_TactileSwitch1 KEYWORD2
getStatus_TactileSwitch2 KEYWORD2
getdata_Accelerometer_xaxis KEYWORD2
getdata_Accelerometer_yaxis KEYWORD2
getdata_Accelerometer_zaxis KEYWORD2
getdata_Gyroscope_xaxis KEYWORD2
getdata_Gyroscope_yaxis KEYWORD2
getdata_Gyroscope_zaxis KEYWORD2
getdata_Magnetometer_xaxis KEYWORD2
getdata_Magnetometer_yaxis KEYWORD2
getdata_Magnetometer_zaxis KEYWORD2
getdata_Proximity KEYWORD2
getdata_Light KEYWORD2
getdata_Sound KEYWORD2
getdata_Temperature KEYWORD2
getdata_Barometer KEYWORD2
getdata_GPS_longitude KEYWORD2
getdata_GPS_latitude KEYWORD2
getangle_Servo1 KEYWORD2
getangle_Servo2 KEYWORD2
send_channel_data KEYWORD2
setParameters KEYWORD2
captureImage KEYWORD2
startRecording KEYWORD2
stopRecording KEYWORD2
flashMode KEYWORD2
setQuality KEYWORD2
zoom KEYWORD2
flipTo KEYWORD2
getRedColor KEYWORD2
getGreenColor KEYWORD2
getBlueColor KEYWORD2
setCalculationMode KEYWORD2
setGridSize KEYWORD2
setColorScheme KEYWORD2
getGridSize KEYWORD2
getColorScheme KEYWORD2
getCalculationMode KEYWORD2
sendSettings KEYWORD2
checkColor KEYWORD2
getColorError KEYWORD2
getGrayScaleColor KEYWORD2
createFile KEYWORD2
createColumn KEYWORD2
send KEYWORD2
stop KEYWORD2
sendMessage KEYWORD2
setTitle KEYWORD2
notifyPhone KEYWORD2
clear KEYWORD2
setDataSpeed KEYWORD2
play KEYWORD2
addToQueue KEYWORD2
stop KEYWORD2
getAccelerometerXaxis KEYWORD2
getAccelerometerYaxis KEYWORD2
getAccelerometerZaxis KEYWORD2
getGyroscopeXaxis KEYWORD2
getGyroscopeYaxis KEYWORD2
getGyroscopeZaxis KEYWORD2
getMagnetometerXaxis KEYWORD2
getMagnetometerYaxis KEYWORD2
getMagnetometerZaxis KEYWORD2
getProximityDistance KEYWORD2
getLightIntensity KEYWORD2
getSoundDecibels KEYWORD2
getTemperature KEYWORD2
getBarometerPressure KEYWORD2
getGPSlongitude KEYWORD2
getGPSlatitude KEYWORD2
getXaxisData KEYWORD2
getYaxisData KEYWORD2
#######################################
# Constants And Literals (LITERAL1)
#######################################
REAR LITERAL1
FRONT LITERAL1
HIGH_QUALITY LITERAL1
LOW_QUALITY LITERAL1
AUTO LITERAL1
OFF LITERAL1
ON LITERAL1
RED LITERAL1
BLUE LITERAL1
GREEN LITERAL1
YELLOW LITERAL1
VIOLET LITERAL1
FROM_DABBLE_FOLDER LITERAL1
INCLUDE_INTERNET_MODULE LITERAL1
INCLUDE_OSCILLOSCOPE_MODULE LITERAL1
INCLUDE_MOTORCONTROL_MODULE LITERAL1
INCLUDE_PINMONITOR_MODULE LITERAL1
INCLUDE_DABBLEINPUTS_MODULE LITERAL1
INCLUDE_GAMEPAD_MODULE LITERAL1
INCLUDE_IOT_MODULE LITERAL1
INCLUDE_SENSOR_MODULE LITERAL1
INCLUDE_TERMINAL_MODULE LITERAL1
INCLUDE_CAMERA_MODULE LITERAL1
INCLUDE_LEDCONTROL_MODULE LITERAL1
INCLUDE_COLORDETECTOR_MODULE LITERAL1
INCLUDE_DATALOGGER_MODULE LITERAL1
INCLUDE_SMS_MODULE LITERAL1
INCLUDE_NOTIFICATION_MODULE LITERAL1
INCLUDE_MUSIC_MODULE LITERAL1
RGB_3BIT LITERAL1
RGB_15BIT LITERAL1
RGB_24BIT LITERAL1
GRAYSCALE_1BIT LITERAL1
GRAYSCALE_4BIT LITERAL1
GRAYSCALE_8BIT LITERAL1
GRID_3x3 LITERAL1
GRID_1x1 LITERAL1
GRID_5x5 LITERAL1
DOMINANT LITERAL1
AVERAGE LITERAL1
NORMAL LITERAL1
CUSTOM_SETTINGS LITERAL1

View File

@ -0,0 +1,10 @@
name=DabbleESP32
version=1.5.1
author=STEMpedia <contact@thestempedia.com>
maintainer=Mimansa Maheshwari <mimansa@thestempedia.com>, Dhrupal Shah <dhrupal@thestempedia.com>
sentence=Dabble is a library to interface ESP32 with Dabble Smartphone app on Arduino IDE.
paragraph=Dabble app transforms a Smartphone into a virtual I/O device. It communicates with hardware like Espressif ESP32 board using in-built Bluetooth (BLE) or evive, and Arduino boards (Uno, Mega, and Nano) using Bluetooth modules like HC-05, HC-06 or HM-10 (BT 2.0, 4.0 or BLE). The app consists of modules that provide access to different functionalities of the smartphone like sensors (accelerometer, GPS, mic, etc.), camera, internet, etc. and consists of certain user interfaces for hardware control and project-making.
category=Communication
url=https://thestempedia.com/product/dabble
architectures=esp32
includes=DabbleESP32.h

View File

@ -0,0 +1,108 @@
#define FROM_DABBLE_LIBRARY
#include "DabbleESP32.h"
#include "CameraModule.h"
CameraModule::CameraModule(): ModuleParent(CAMERA_ID)
{
}
void CameraModule::setParameters(uint8_t rotateTo,uint8_t flashmode, uint8_t quality,uint8_t zoomvalue)
{
Dabble.sendModuleFrame(CAMERA_ID,0,0x01,1,new FunctionArg(1,&rotateTo));
Dabble.sendModuleFrame(CAMERA_ID,0,0x01,1,new FunctionArg(1,&flashmode));
Dabble.sendModuleFrame(CAMERA_ID,0,0x01,1,new FunctionArg(1,&quality));
Dabble.sendModuleFrame(CAMERA_ID,0,0x02,1,new FunctionArg(1,&zoomvalue));
}
void CameraModule::captureImage()
{
Dabble.sendModuleFrame(CAMERA_ID,0,0x01,1,new FunctionArg(1,&captureimage));
}
void CameraModule::startRecording()
{
Dabble.sendModuleFrame(CAMERA_ID,0,0x01,1,new FunctionArg(1,&startVideo));
}
void CameraModule::stopRecording()
{
Dabble.sendModuleFrame(CAMERA_ID,0,0x01,1,new FunctionArg(1,&stopVideo));
}
void CameraModule::flashMode(uint8_t a)
{
Dabble.sendModuleFrame(CAMERA_ID,0,0x01,1,new FunctionArg(1,&a));
}
void CameraModule::setQuality(uint8_t a)
{
Dabble.sendModuleFrame(CAMERA_ID,0,0x01,1,new FunctionArg(1,&a));
}
void CameraModule::zoom(uint8_t a)
{
Dabble.sendModuleFrame(CAMERA_ID,0,0x02,1,new FunctionArg(1,&a));
}
void CameraModule::flipTo(uint8_t direction)
{
if(direction == 1) //Rear
{
direction = 0x05;
Dabble.sendModuleFrame(CAMERA_ID,0,0x01,1,new FunctionArg(1,&direction));
}
else if(direction == 2) //Front
{
direction = 0x04;
Dabble.sendModuleFrame(CAMERA_ID,0,0x01,1,new FunctionArg(1,&direction));
}
else
Dabble.sendModuleFrame(CAMERA_ID,0,0x01,1,new FunctionArg(1,&direction));
}
void CameraModule::cameraAction(uint8_t a)
{
if(a == 1)
{
Dabble.sendModuleFrame(CAMERA_ID,0,0x01,1,new FunctionArg(1,&captureimage));
}
if(a == 2)
{
Dabble.sendModuleFrame(CAMERA_ID,0,0x01,1,new FunctionArg(1,&startVideo));
}
if(a == 3)
{
Dabble.sendModuleFrame(CAMERA_ID,0,0x01,1,new FunctionArg(1,&stopVideo));
}
}
void CameraModule::cameraConfig(uint8_t flash,uint8_t quality,uint8_t zoom)
{
if(flash == 1) //On
{
flash = 0x06;
Dabble.sendModuleFrame(CAMERA_ID,0,0x01,1,new FunctionArg(1,&flash));
}
else if(flash == 2) //Auto
{
flash = 0x07;
Dabble.sendModuleFrame(CAMERA_ID,0,0x01,1,new FunctionArg(1,&flash));
}
else if(flash == 3) //Off
{
flash = 0x08;
Dabble.sendModuleFrame(CAMERA_ID,0,0x01,1,new FunctionArg(1,&flash));
}
if(quality == 1)
{
quality = 0x09; //High
Dabble.sendModuleFrame(CAMERA_ID,0,0x01,1,new FunctionArg(1,&quality));
}
else if(quality == 2)
{
quality = 0x0A; //Low
Dabble.sendModuleFrame(CAMERA_ID,0,0x01,1,new FunctionArg(1,&quality));
}
Dabble.sendModuleFrame(CAMERA_ID,0,0x02,1,new FunctionArg(1,&zoom));
}

View File

@ -0,0 +1,43 @@
#ifndef CameraModule_h
#define CameraModule_h
#include "ModuleParent.h"
#define REAR 0x05
#define FRONT 0x04
#define ON 0x06
#define OFF 0x08
#define AUTO 0x07
#define HIGH_QUALITY 0x09
#define LOW_QUALITY 0x0A
class CameraModule:public ModuleParent
{
public:
CameraModule();
//Arduino
void setParameters(uint8_t,uint8_t,uint8_t,uint8_t); //Direction,flash,quality,zoom
void captureImage(); //Camera Direction
void startRecording();
void stopRecording();
void flashMode(byte); //On, Off, Auto
void setQuality(uint8_t); //High, Low
void zoom(uint8_t); // enter zoom in % from 1 to 100.
//Arduino and Pictoblox
void flipTo(uint8_t); //1 Front 2 Rear
//Pictoblox
void cameraAction(uint8_t); //1 captureImage,2 startVideo,3 stopVideo
void cameraConfig(uint8_t,uint8_t,uint8_t);//flash,quality,zoom
private:
uint8_t captureimage = 0x01;
uint8_t startVideo = 0x02;
uint8_t stopVideo = 0x03;
};
extern CameraModule Camera;
#endif

View File

@ -0,0 +1,59 @@
/*
CircularBuffer.h - circular buffer library for Arduino.
Copyright (c) 2009 Hiroki Yagita.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef CIRCULARBUFFER_h
#define CIRCULARBUFFER_h
#include <inttypes.h>
template <typename T, uint16_t Size>
class CircularBuffer {
public:
CircularBuffer() :
wp_(buf_), rp_(buf_), tail_(buf_+Size), remain_(0) {}
~CircularBuffer() {}
void push(T value) {
if(remain_==Size)return;
*wp_++ = value;
remain_++;
if (wp_ == tail_) wp_ = buf_;
}
T pop() {
T result = *rp_++;
remain_--;
if (rp_ == tail_) rp_ = buf_;
return result;
}
int remain() const {
return remain_;
}
private:
T buf_[Size];
T *wp_;
T *rp_;
T *tail_;
uint16_t remain_;
};
#endif

View File

@ -0,0 +1,444 @@
#define FROM_DABBLE_LIBRARY
#include "DabbleESP32.h"
#include "ColorDetectorModule.h"
int checksettings=0;
float idealColorValue[5][3] ={ {255, 0, 0}, //RGB for red
{0, 255, 0}, //RGB for Green
{0, 0, 255}, //RGB for Blue
{255, 242, 0}, //RGB for Yellow
{148, 0, 211}, //RGB for Violet
};
ColorDetectorModule::ColorDetectorModule():ModuleParent(COLORDETECTOR_ID),ColorPrediction()
{
}
void ColorDetectorModule::sendSettings(void(*function)(void))
{
checksettingsCallBack=true;
settingsCallBack = function;
}
void ColorDetectorModule::sendSettings(uint8_t Grid,uint8_t calcMode,uint8_t ColorScheme)
{
checksettings =3;
#ifdef DEBUG
Serial.print("Settings Callback: ");
Serial.println(checksettings);
#endif
if(Grid == 1) //1x1
{
gridSize = 1;
}
else if(Grid == 2) //3x3
{
gridSize = 3;
}
else if(Grid == 3) //5x5
{
gridSize = 5;
}
if(calcMode == 1) //Dominant
{
calculationMode = 1;
}
else if(calcMode == 2) // Average
{
calculationMode = 2;
}
if(ColorScheme == 6 ) //GRAYSCALE_1BIT
{
colorScheme = 1 ;
}
else if(ColorScheme == 5 ) //GRAYSCALE_4BIT
{
colorScheme = 4;
}
else if(ColorScheme == 4 ) //GRAYSCALE_8BIT
{
colorScheme = 8 ;
}
else if(ColorScheme == 3 ) //Rgb_3bit
{
colorScheme = 3 ;
}
else if(ColorScheme == 2 ) //Rgb_15bit
{
colorScheme = 15 ;
}
else if(ColorScheme == 1) //Rgb_24bit
{
colorScheme = 24;
}
}
void ColorDetectorModule::processData()
{
if(checksettings != 0)
{
if(checksettings == 3)
{
Dabble.sendModuleFrame(COLORDETECTOR_ID,0,COLOR_SCHEME,1,new FunctionArg(1,&colorScheme));
checksettings = 2;
}
else if(checksettings == 2)
{
Dabble.sendModuleFrame(COLORDETECTOR_ID,0,GRID_SETTING,1,new FunctionArg(1,&gridSize));
checksettings =1;
}
else if(checksettings == 1)
{
Dabble.sendModuleFrame(COLORDETECTOR_ID,0,COLOR_CALCULATION_TYPE,1,new FunctionArg(1,&calculationMode));
checksettings =0;
}
}
if(checksettingsCallBack == true)
{
checksettingsCallBack=false;
(*settingsCallBack)();
}
byte functionID = getDabbleInstance().getFunctionId();
if(functionID == COLOR_DATA )
{
//Second arg line onwards color values are stored.
if(currentArgnumber != getDabbleInstance().getArgumentNo())
{
if(currentArgnumber!=0)
{
for (int i = 0; i < currentArgnumber-1; i++)
{
delete [] colorArray[i];
}
delete [] colorArray;
}
colorArray = new uint8_t*[getDabbleInstance().getArgumentNo()-1];
for (int i = 0; i < getDabbleInstance().getArgumentNo()-1; i++) //color values comes from second line
{
colorArray[i] = new uint8_t[3];
}
}
currentArgnumber=getDabbleInstance().getArgumentNo();
for (int i = 1; i < getDabbleInstance().getArgumentNo(); i++) //color values comes from second line
{
for (int j = 0; j < 3; j++)
{
colorArray[i-1][j] = getDabbleInstance().getArgumentData(i)[j];
#ifdef DEBUG
Serial.print(colorArray[i-1][j]);
Serial.print(" ");
#endif
}
#ifdef DEBUG
Serial.println();
#endif
}
}
}
void ColorDetectorModule::setColorScheme(byte bitScheme)
{
Dabble.sendModuleFrame(COLORDETECTOR_ID,0,COLOR_SCHEME,1,new FunctionArg(1,&bitScheme));
}
void ColorDetectorModule::setGridSize(byte gridsize)
{
Dabble.sendModuleFrame(COLORDETECTOR_ID,0,GRID_SETTING,1,new FunctionArg(1,&gridsize));
}
void ColorDetectorModule::setCalculationMode(byte calculationMode)
{
Dabble.sendModuleFrame(COLORDETECTOR_ID,0,COLOR_CALCULATION_TYPE,1,new FunctionArg(1,&calculationMode));
}
int ColorDetectorModule::getRedColor()
{
if(currentArgnumber !=0 )
{
return colorArray[0][0];
}
else
{
return -1;
}
}
int ColorDetectorModule::getGreenColor()
{
if(currentArgnumber !=0 )
{
return colorArray[0][1];
}
else
{
return -1;
}
}
int ColorDetectorModule::getBlueColor()
{
if(currentArgnumber !=0 )
{
return colorArray[0][2];
}
else
{
return -1;
}
}
int ColorDetectorModule::getRedColor(byte row, byte col)
{
if(currentArgnumber!=0)
{
if(row == 0)
{
return colorArray[col][0];
}
else if(row == 1)
{
return colorArray[(currentArgnumber/gridSize)+col][0];
}
else if(row == 2)
{
return colorArray[((currentArgnumber/gridSize)*2)+col][0];
}
else if(row == 3)
{
return colorArray[((currentArgnumber/gridSize)*3)+col][0];
}
else if(row == 4)
{
return colorArray[((currentArgnumber/gridSize)*4)+col][0];
}
}
else
{
return -1;
}
}
int ColorDetectorModule::getGreenColor(byte row, byte col)
{
if(currentArgnumber!=0)
{
if(row == 0)
{
return colorArray[col][1];
}
else if(row == 1)
{
return colorArray[(currentArgnumber/gridSize)+col][1];
}
else if(row == 2)
{
return colorArray[((currentArgnumber/gridSize)*2)+col][1];
}
else if(row == 3)
{
return colorArray[((currentArgnumber/gridSize)*3)+col][1];
}
else if(row == 4)
{
return colorArray[((currentArgnumber/gridSize)*4)+col][1];
}
}
else
{
return -1;
}
}
int ColorDetectorModule::getBlueColor(byte row, byte col)
{
if(currentArgnumber!=0)
{
if(row == 0)
{
return colorArray[col][2];
}
else if(row == 1)
{
return colorArray[(currentArgnumber/gridSize)+col][2];
}
else if(row == 2)
{
return colorArray[((currentArgnumber/gridSize)*2)+col][2];
}
else if(row == 3)
{
return colorArray[((currentArgnumber/gridSize)*3)+col][2];
}
else if(row == 4)
{
return colorArray[((currentArgnumber/gridSize)*4)+col][2];
}
}
else
{
return -1;
}
}
uint8_t ColorDetectorModule::getGridSize()
{
return getDabbleInstance().getArgumentData(0)[2];;
}
uint8_t ColorDetectorModule::getColorScheme()
{
return getDabbleInstance().getArgumentData(0)[0];;
}
uint8_t ColorDetectorModule::getCalculationMode()
{
return getDabbleInstance().getArgumentData(0)[1];;
}
int ColorDetectorModule::getColorValue(uint8_t colorName,uint8_t Row,uint8_t Col)
{
if(gridSize == 3 && (Row < 3 && Col < 3))
{
if(colorName == 1) //Red
{
return getRedColor(Row,Col);
}
else if(colorName == 2) //Green
{
return getGreenColor(Row,Col);
}
else if(colorName == 3) //Blue
{
return getBlueColor(Row,Col);
}
else if(colorName == 4) //Black
{
if((colorScheme == GRAYSCALE_1BIT) || (colorScheme == GRAYSCALE_4BIT) || (colorScheme == GRAYSCALE_8BIT))
return getRedColor(Row,Col);
else
return -1;
}
}
else if(gridSize == 5 && (Row<5 && Col<5))
{
if(colorName == 1) //Red
{
return getRedColor(Row,Col);
}
else if(colorName == 2) //Green
{
return getGreenColor(Row,Col);
}
else if(colorName == 3) //Blue
{
return getBlueColor(Row,Col);
}
else if(colorName == 4) //Black
{
if((colorScheme == GRAYSCALE_1BIT) || (colorScheme == GRAYSCALE_4BIT) || (colorScheme == GRAYSCALE_8BIT))
return getRedColor(Row,Col);
else
return -1;
}
}
else if(gridSize == 1 && (Row<1 && Col<1))
{
if(colorName == 1) //Red
{
return getRedColor();
}
else if(colorName == 2) //Green
{
return getGreenColor();
}
else if(colorName == 3) //Blue
{
return getBlueColor();
}
else if(colorName == 4) //Black
{
if((colorScheme == GRAYSCALE_1BIT) || (colorScheme == GRAYSCALE_4BIT) || (colorScheme == GRAYSCALE_8BIT))
return getRedColor();
else
return -1;
}
}
else
{
return -1;
}
}
int ColorDetectorModule::getGrayScaleColor(byte row,byte col)
{
if(currentArgnumber!=0 && (colorScheme == GRAYSCALE_1BIT || colorScheme == GRAYSCALE_4BIT || colorScheme == GRAYSCALE_8BIT))
{
if(row == 0)
{
return colorArray[col][0];
}
else if(row == 1)
{
return colorArray[(currentArgnumber/gridSize)+col][0];
}
else if(row == 2)
{
return colorArray[((currentArgnumber/gridSize)*2)+col][0];
}
else if(row == 3)
{
return colorArray[((currentArgnumber/gridSize)*3)+col][0];
}
else if(row == 4)
{
return colorArray[((currentArgnumber/gridSize)*4)+col][0];
}
}
else
{
return -1;
}
}
ColorPrediction::ColorPrediction(){
min_deviation = 255;
}
bool ColorPrediction::checkColor(int *colorValue, uint8_t colorName)
{
if((colorValue[0]==-1) || (colorValue[1]==-1) || (colorValue[2]==-1))
{
return 0;
}
else{
min_deviation = 255;
for(int i = 0;i<5;i++)
{
deviation = sqrt((sq(idealColorValue[i][0] - colorValue[0]) + sq(idealColorValue[i][1] - colorValue[1]) + sq(idealColorValue[i][2] - colorValue[2])) / 3);
if(min_deviation>deviation)
{
min_deviation = deviation;
colorFlag = i+1;
}
}
if(colorFlag == colorName)
return 1;
else
return 0;
}
}
float ColorPrediction::getColorError(uint8_t *colorValue,uint8_t *referenceValue)
{
if((colorValue[0]==-1) || (colorValue[1]==-1) || (colorValue[2]==-1))
{
return -1;
}
else
{
deviation = sqrt((sq(referenceValue[0] - colorValue[0]) + sq(referenceValue[1] - colorValue[1]) + sq(referenceValue[2] - colorValue[2])) / 3);
return deviation;
}
}

View File

@ -0,0 +1,82 @@
#ifndef ColorDetectorModule_H_
#define ColorDetectorModule_H_
#include "ModuleParent.h"
//Function Id
#define GRID_SETTING 0x01
#define COLOR_CALCULATION_TYPE 0x02 // for Dominant or average
#define COLOR_SCHEME 0x03 // bit size of color
#define COLOR_DATA 0x04
//Literals
#define RGB_3BIT 3
#define RGB_15BIT 15
#define RGB_24BIT 24
#define GRAYSCALE_1BIT 1
#define GRAYSCALE_4BIT 4
#define GRAYSCALE_8BIT 8
//#define GRID_5x1 0x04
#define GRID_3x3 0x03
#define GRID_1x1 0x01
#define GRID_5x5 0x05
#define DOMINANT 0x01
#define AVERAGE 0x02
#define RED 0x01
#define GREEN 0x02
#define BLUE 0x03
#define YELLOW 0x04
#define VIOLET 0x05
class ColorPrediction
{
public:
ColorPrediction();
bool checkColor(int *colorValue,uint8_t colorName);
float getColorError(uint8_t *colorValue,uint8_t *referenceValue);
int colorFlag=0;
float min_deviation = 255;
float deviation = 0;
};
class ColorDetectorModule:public ModuleParent, public ColorPrediction
{
public:
ColorDetectorModule();
//Arduino
void setColorScheme(byte);
void setGridSize(byte);
void setCalculationMode(byte);
int getRedColor();
int getBlueColor();
int getGreenColor();
int getRedColor(byte,byte); //for different blocks of grid
int getBlueColor(byte,byte); //for different blocks of grid
int getGreenColor(byte,byte); //for different blocks of grid
uint8_t getGridSize();
uint8_t getColorScheme();
uint8_t getCalculationMode();
int getGrayScaleColor(byte,byte);
void sendSettings(void(*)(void));
//Pictoblox
void sendSettings(uint8_t,uint8_t,uint8_t);
int getColorValue(uint8_t,uint8_t,uint8_t);
private:
void processData();
void (*settingsCallBack)(void);
bool checksettingsCallBack;
uint8_t** colorArray;
uint8_t currentArgnumber=0;
uint8_t gridSize=0;
uint8_t colorScheme=0;
uint8_t calculationMode=0;
};
extern ColorDetectorModule ColorDetector;
#endif

View File

@ -0,0 +1,716 @@
#define FROM_DABBLE_LIBRARY
#include "stdarg.h"
#include "DabbleESP32.h"
bool callBackForDataLogger = false;
void (*dataLoggerCallBack)(void);
bool DabbleClass::isInit=false;
bool DabbleClass::isSws=false;
byte DabbleClass::ModulesCounter=0;
unsigned long DabbleClass::lastTimeFrameSent=0;
unsigned long DabbleClass::argumentDataBytesTimeReceived=0;
bool DabbleClass::inACallback=false;
bool DabbleClass::callbacksInterrupts=false;
bool DabbleClass::isFirstFrame=false;
ModuleParent * DabbleClass::ModulesArray[]={0};
//byte DabbleClass::requestsCounter=0;
//HttpRequest ** DabbleClass::requestsArray=0;
uint8_t FrameLimits[4][18] = {{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17}, //Module-ID
{3, 3, 2, 3, 9, 4, 2, 0, 2, 3, 3, 4, 6, 5, 3, 1, 1, 3}, //Funtcion_ID
{1, 1,255, 1, 3, 1, 1, 0, 2, 1, 1, 26, 2, 1, 1, 2, 1, 100}, //Arg1
{5, 2,255, 32, 4, 2, 1, 0, 4, 2, 1, 3, 50, 255, 1, 1, 2, 255}}; //Arg2
//Class Constructor
DabbleClass::DabbleClass()
{
Module=0;
verificationByte=0;
functions=0;
counter=0;
argumentcounter=0;
datalengthcounter=0;
argumentnumber=0;
argumentsize=0;
endFrame=0;
numberOfDataMalloced=0;
isArgumentsNumberMalloced=false;
isArgumentLengthMalloced=false;
callbacksInterrupts=false;
framestart =false;
isDabbleConnected =false;
isAppConnectionCallBack = false;
isModuleFrameCallback = false;
isSerialDataCallback = false;
dontDelay = false;
}
//Library Starter
void DabbleClass::begin(std::string bleName)
{
esp32ble.begin(bleName);
init();
}
//Blocking function
void DabbleClass::waitForAppConnection()
{
isDabbleConnected = false;
while(!isDabbleConnected)
{
Dabble.processInput();
}
}
void DabbleClass::init()
{
isInit=true;
sendModuleFrame(Dabble_ID,0,CHECK_CONNECTION,0);
/*if(requestsArray!=0){
for(int i=0;i<requestsCounter;i++)
requestsArray[i]->sendInitFrame();
free(requestsArray);
requestsCounter=0;
}*/
}
//Library Starter
void DabbleClass::addToModulesArray(ModuleParent * Module)
{
if(ModulesCounter==MODULE_NO) return;
ModulesArray[ModulesCounter++] = Module;
}
// #ifdef INTERNET_Module
/*void DabbleClass::addToUnSentRequestsArray(HttpRequest * request)
{
if(requestsCounter==MAX_NO_OF_REQUESTS) return;
if(requestsCounter<=0)
requestsArray=(HttpRequest**)malloc(sizeof(HttpRequest*)*MAX_NO_OF_REQUESTS);
requestsArray[requestsCounter++] = request;
}*/
// #endif
bool DabbleClass::isInitialized()
{
return isInit;
}
bool DabbleClass::isSoftwareSerial()
{
return isSws;
}
void DabbleClass::setOnNewModuleFrame(void (*userFunction)(byte ModuleID, byte functionID, byte argNo,byte *argumentL,byte **arguments))
{
isModuleFrameCallback=true;
ModuleFrameCallback=userFunction;
}
void DabbleClass::setOnNewSerialData(void (*userFunction)(byte))
{
isSerialDataCallback=true;
serialDataCallback=userFunction;
}
void DabbleClass::appWrite(byte command)
{
if(isInit){
esp32ble.write(command);
#ifdef DEBUG
Serial.print("Sent: ");
Serial.println(command,HEX);
#endif
}
if(!dontDelay)
{
::delay(2);
}
}
//Frame Sender for Output Modules
void DabbleClass::sendModuleFrame(byte ModuleID, byte instanceID, byte functionID, byte argNo, ...)
{
unsigned long mill=millis()+1;
unsigned long localLastTimeFrameSent=lastTimeFrameSent;
if(ModuleID!=Dabble_ID&&isFirstFrame&&localLastTimeFrameSent&&(mill-localLastTimeFrameSent)<TIME_GAP){
/*if(inACallback){
DabbleClass TempDabble;
ModuleParent::setDabbleInstance(TempDabble);
while((millis()<(TIME_GAP+localLastTimeFrameSent))||TempDabble.framestart)
{
if(TempDabble.DabbleSerial->available())
TempDabble.processInput(TempDabble.DabbleSerial->read());
}
ModuleParent::unSetDabbleInstance();
}else*/
while((millis()<(TIME_GAP+localLastTimeFrameSent))||framestart)
{
if(esp32ble.available())
Dabble.processInput(esp32ble.read());
}
}
isFirstFrame=true;
va_list arguments ;
va_start (arguments,argNo);
appWrite((byte)START_OF_FRAME);
//appWrite(LIBRARY_VERSION);
appWrite(ModuleID);
//appWrite(getVerificationByte());
appWrite(functionID);
appWrite(argNo);
//appWrite(255-argNo);
for (int i=0 ; i<argNo ; i++)
{
FunctionArg * temp = va_arg(arguments, FunctionArg *);
appWrite(temp->getLength());
//appWrite(255-(temp->getLength()));
for (int j=0 ; j<temp->getLength() ; j++)
{
byte* tempData=temp->getData();
appWrite(tempData[j]);
}
delete(temp);
}
appWrite((byte)END_OF_FRAME);
va_end(arguments);
if(ModuleID!=Dabble_ID)lastTimeFrameSent=millis()+1;
#ifdef DEBUG
Serial.println();
#endif
}
void DabbleClass::sendModuleFrame(byte ModuleID, byte instanceID, byte functionID, byte argNo, FunctionArg ** arguments)
{
unsigned long mill=millis()+1;
unsigned long localLastTimeFrameSent=lastTimeFrameSent;
if(ModuleID!=Dabble_ID&&isFirstFrame&&localLastTimeFrameSent&&(mill-localLastTimeFrameSent)<TIME_GAP){
/*if(inACallback){
DabbleClass TempDabble;
ModuleParent::setDabbleInstance(TempDabble);
while((millis()<(TIME_GAP+localLastTimeFrameSent))||TempDabble.framestart)
{
if(TempDabble.DabbleSerial->available())
TempDabble.processInput(TempDabble.DabbleSerial->read());
}
ModuleParent::unSetDabbleInstance();
}else*/
while((millis()<(TIME_GAP+localLastTimeFrameSent))||framestart)
{
if(esp32ble.available())
Dabble.processInput(esp32ble.read());
}
}
isFirstFrame=true;
appWrite((byte)START_OF_FRAME);
//appWrite(LIBRARY_VERSION);
appWrite(ModuleID);
//appWrite(getVerificationByte());
appWrite(functionID);
appWrite(argNo);
//appWrite(255-argNo);
for (int i=0 ; i<argNo ; i++)
{
appWrite(arguments[i]->getLength());
//appWrite(255-(arguments[i]->getLength()));
for (int j=0 ; j<arguments[i]->getLength() ; j++)
{
byte* tempData=arguments[i]->getData();
appWrite(tempData[j]);
}
}
appWrite((byte)END_OF_FRAME);
if(ModuleID!=Dabble_ID)lastTimeFrameSent=millis()+1;
#ifdef DEBUG
Serial.println();
#endif
}
bool DabbleClass::isAppConnected()
{
return isDabbleConnected;
}
void DabbleClass::setOnAppConnected(void (*userFunction)(bool isAppConnected))
{
isAppConnectedCallBack = userFunction;
isAppConnectionCallBack = true;
}
//Module_ID Getter
byte DabbleClass::getModuleId()
{
return Module;
}
//Funtcion_ID Getter
byte DabbleClass::getFunctionId()
{
return functions;
}
//ArgumentsNumber Getter
byte DabbleClass::getArgumentNo()
{
return argumentnumber;
}
//ArgumentLength Getter
byte DabbleClass::getArgumentLength(byte x)
{
return argumentL[x];
}
byte DabbleClass::getScreenId()
{
return screenId;
//if(getModuleId() == 0 &&
}
byte DabbleClass::readModuleId()
{
return readModuleID;
}
//Data Getter
byte * DabbleClass::getArgumentData(byte x)
{
if(argumentL[x]!=0)
{
return arguments[x];
}
else return NULL;
}
//Convert float to array of bytes
void DabbleClass::convertFloatToBytes(float data, byte * out)
{
FloatUnion f2bUnion;
f2bUnion.number = data;
out[0]=f2bUnion.floatBytes[0];
out[1]=f2bUnion.floatBytes[1];
out[2]=f2bUnion.floatBytes[2];
out[3]=f2bUnion.floatBytes[3];
}
//Convert array of bytes to float
float DabbleClass::convertBytesToFloat(byte *data)
{
FloatUnion b2fUnion;;
b2fUnion.floatBytes[0] = data[0];
b2fUnion.floatBytes[1] = data[1];
b2fUnion.floatBytes[2] = data[2];
b2fUnion.floatBytes[3] = data[3];
return b2fUnion.number;
}
//Incomming Frames processing
void DabbleClass::processInput(int data) {
#ifdef DEBUG
Serial.write(data);
//Serial.print(" ");
#endif
if(data==-1){
return;
}
if((millis() - argumentDataBytesTimeReceived) > 2000 && argumentDataBytesTimeReceived !=0 && framestart)
{
freeMemoryAllocated();
}
argumentDataBytesTimeReceived = millis();
if(!framestart&&data==START_OF_FRAME)
{
freeMemoryAllocated();
counter=0;
framestart=true;
arguments=0;
argumentL=0;
counter++;
}
else if(counter==3&&framestart) //data is the no of arguments
{
#ifdef DEBUG
Serial.print("C3 ");
#endif
datalengthcounter=0;
argumentcounter=0;
argumentnumber=data;
if(argumentnumber > FrameLimits[2][Module])
{
framestart = false;
counter = 0;
return;
}
if(argumentnumber !=0)
{
isArgumentsNumberMalloced=true;
isArgumentLengthMalloced=true;
arguments = new byte* [argumentnumber];
argumentL = new byte [argumentnumber];
}
counter++;
}
else if (counter==4&&framestart) // data is the first argument length
{
#ifdef DEBUG
Serial.print("C4 ");
#endif
datalengthcounter = 0;
argumentsize = data; //size of each argument line
if(argumentsize > FrameLimits[3][Module])
{
framestart = false;
counter = 0;
return;
}
if(argumentnumber !=0)
{
argumentL[argumentcounter] = argumentsize;
arguments[argumentcounter] = new byte[argumentsize];
counter++;
}
else
{
counter = 6; //move to endframe section
}
numberOfDataMalloced++;
}
else if (counter==5&&framestart)
{
#ifdef DEBUG
Serial.print("C5 ");
#endif
if(argumentnumber !=0)
{
if(datalengthcounter < argumentsize)
{
arguments[argumentcounter][datalengthcounter++] = data;
}
if(datalengthcounter == argumentsize)
{
counter = 4;
argumentcounter++;
}
if(argumentnumber == argumentcounter) //check if data stored in all lines
{
counter = 6;
}
}
}
else if(counter==6&&framestart)
{
#ifdef DEBUG
Serial.print("C6 ");
#endif
endFrame=data;
if(endFrame==END_OF_FRAME) //if the endframe is equal to zero send to Modules and free memory
{
framestart=false;
//Serial.println("Sent to modules");
sendToModules();
/* if(isModuleFrameCallback && Module!=0)
{
enteringACallback();
ModuleFrameCallback(Module,functions,argumentnumber,argumentL,arguments);
exitingACallback();
}*/
freeMemoryAllocated();
#ifdef DEBUG
Serial.println();
#endif
}
else //if endframe wasn't equal to zero make sure that the memory is free anyway
{
freeMemoryAllocated();
}
}
else if(framestart){
if(counter==1){
Module=data;
bool found = false;
if(Module == Dabble_ID || isModuleFrameCallback) found = true;
else
{
for (int i=0;i<ModulesCounter;i++) {
if (Module == ModulesArray[i]->getModuleId()){
found = true;
/*#ifdef DEBUG
Serial.print("Module: ");
Serial.print(Module, HEX);
Serial.print(" ");
#endif*/
}
}
}
if (!found) {
framestart=false;
freeMemoryAllocated();
return;
}
}
else if(counter==2){
functions=data;
if(functions > FrameLimits[1][Module])
{
counter = 0;
framestart=false;
return;
}
#ifdef DEBUG
Serial.print("C2 ");
#endif
}
counter++;
}
}
void DabbleClass::processInput()
{
if(esp32ble.available())
{
isDabbleConnected = true;
while(esp32ble.available())
{
byte data=esp32ble.read();
/*#ifdef DEBUG
Serial.print(data);
Serial.print(" ");
#endif*/
processInput(data);
/*if(isSerialDataCallback)
{
enteringACallback();
serialDataCallback(data);
exitingACallback();
}*/
}
/*#ifdef DEBUG
Serial.println();
#endif*/
}
}
void DabbleClass::freeMemoryAllocated(){
framestart=false;
if(isArgumentsNumberMalloced)
{
for(int i=0;i<argumentnumber;i++)
{
delete [] arguments[i];
#ifdef DEBUG
Serial.print("F3 ");
#endif
}
delete [] arguments;
arguments=NULL;
numberOfDataMalloced=0;
isArgumentsNumberMalloced=false;
}
if(isArgumentLengthMalloced)
{
delete [] argumentL;
isArgumentLengthMalloced = false;
#ifdef DEBUG
Serial.print("F2 ");
#endif
argumentL=NULL;
}
}
//Data Sender to Input Modules
void DabbleClass::sendToModules()
{
//Checking the Module-ID
byte number_Of_Module= Dabble.getModuleId();
// Serial.println(Dabble.getArgumentData(0)[0]);
switch (number_Of_Module)
{
case Dabble_ID:processFrame();break;
default:
for(int i=0 ;i<ModulesCounter;i++)
{
ModulesArray[i]->processFrame();
}
}
}
void DabbleClass::processFrame(){
byte functionId = getFunctionId();
if(argumentnumber !=0)
{
readModuleID = getArgumentData(0)[0];
screenId = getArgumentData(0)[1];
}
if(callBackForDataLogger == true)
{
callBackForDataLogger =false;
(*dataLoggerCallBack)();
}
//Check the function ID
if(functionId == BOARDID_REQUEST)
{
// uint8_t BoardId_evive[1]={0x01};
uint8_t BoardId_Mega[4] = {0x02,1,5,1};
uint8_t BoardId_Uno[4] = {0x03,1,5,1};
uint8_t BoardId_Nano[4] = {0x04,1,5,1};
uint8_t BoardId_ESP32[4] = {0x06,1,5,1};
uint8_t BoardId_Other[4] = {0x05,1,5,1};
#if ((defined(ARDUINO_AVR_MEGA2560)) || (defined(ARDUINO_AVR_MEGA)))
sendModuleFrame(Dabble_ID,0,BOARDID_REQUEST,1,new FunctionArg(4,BoardId_Mega));
#elif(defined(ARDUINO_AVR_NANO))
sendModuleFrame(Dabble_ID,0,BOARDID_REQUEST,1,new FunctionArg(4,BoardId_Nano));
#elif(defined(ARDUINO_AVR_UNO))
sendModuleFrame(Dabble_ID,0,BOARDID_REQUEST,1,new FunctionArg(4,BoardId_Uno));
#elif(ESP32)
sendModuleFrame(Dabble_ID,0,BOARDID_REQUEST,1,new FunctionArg(4,BoardId_ESP32));
#else
sendModuleFrame(Dabble_ID,0,BOARDID_REQUEST,1,new FunctionArg(4,BoardId_Other));
#endif
/* #if (defined(__AVR_ATmega2560__))
sendModuleFrame(Dabble_ID,0,BOARDID_REQUEST,1,new FunctionArg(4,BoardId_Mega));
#elif (defined(__AVR_ATmega328P__))
sendModuleFrame(Dabble_ID,0,BOARDID_REQUEST,1,new FunctionArg(4,BoardId_Uno));
#else
sendModuleFrame(Dabble_ID,0,BOARDID_REQUEST,1,new FunctionArg(4,BoardId_Other));
#endif*/
}
/*else if(functionId == LIBRARY_VERSION_REQUEST)
{
sendModuleFrame(Dabble_ID,0,SEND_LIBRARY_VERSION,0);
}
else if(functionId == LIBRARY_TESTING_REQUEST)
{
if(!memcmp("Are you ok?",getArgumentData(0),11))
{
const char * responseString = "Yup, I'm feeling great!";
byte testAnswer = 0;
int sumOfData = 0;
for(int i = 0 ; i < getArgumentLength(1) ; i++)
{
sumOfData+= getArgumentData(1)[i];
}
testAnswer = sumOfData%256;
sendModuleFrame(Dabble_ID,0x00,LIBRARY_TESTING_RESPONSE,2,new FunctionArg(23,(byte *)responseString),new FunctionArg(1,&testAnswer));
}
}*/
}
//PulseWidthModulation Getter
unsigned char DabbleClass::analogRead(int pin)
{
double period=(double)pulseIn(pin,HIGH)+(double)pulseIn(pin,LOW);;
double duty=(double)pulseIn(pin,HIGH);
double fraction=duty/period;
unsigned char pwm_out=(unsigned char)(ceil)(fraction*255);
return pwm_out;
}
void DabbleClass::enteringACallback()
{
if(!isInACallback())
{
inACallback=true;
dontDelay = true;
sendModuleFrame(Dabble_ID,0,CALLBACK_ENTERED,0);
dontDelay = false;
}
}
void DabbleClass::exitingACallback()
{
if(isInACallback())
{
inACallback=false;
dontDelay = true;
sendModuleFrame(Dabble_ID,0,CALLBACK_EXITED,0);
dontDelay = false;
}
}
bool DabbleClass::isInACallback()
{
return inACallback && !callbacksInterrupts;
}
bool DabbleClass::isCallbacksInterruptsSet()
{
return callbacksInterrupts;
}
void DabbleClass::disableCallbacksInterrupts()
{
callbacksInterrupts=false;
}
void DabbleClass::enableCallbacksInterrupts()
{
callbacksInterrupts=true;
}
void DabbleClass::delay(unsigned long time)
{
unsigned long now=millis();
/*if(inACallback)
{
DabbleClass TempDabble;
ModuleParent::setDabbleInstance(TempDabble);
while((millis()<(now+time))||TempDabble.framestart)
{
if(TempDabble.DabbleSerial->available())
TempDabble.processInput(TempDabble.DabbleSerial->read());
}
ModuleParent::unSetDabbleInstance();
}else*/
while((millis()<(now+time))||framestart)
{
#if (defined(ESP32))
if(esp32ble.available())
Dabble.processInput(esp32ble.read());
#else
if(DabbleSerial->available())
Dabble.processInput(DabbleSerial->read());
#endif
}
}
DabbleClass Dabble;
//Instantiating Object
/*#if (defined(__AVR_ATmega32U4__) || \
defined(ARDUINO_LINUX) || \
defined(__MK20DX128__) || \
defined(__MK20DX256__) || \
defined(__MKL26Z64__) || \
defined(_VARIANT_ARDUINO_101_X_) || \
defined(_VARIANT_ARDUINO_ZERO_))
void serialEvent1()
#else
void serialEvent3()
#endif
{
if(!Dabble.isSoftwareSerial()) Dabble.processInput();
}*/
byte DabbleClass::getVerificationByte()
{
byte randomValue = (byte)random(0,16);
byte randomValueComplement = ~(randomValue);
randomValue&=0x0F;
randomValue = randomValue|(randomValueComplement<<4);
return randomValue;
}

View File

@ -0,0 +1,253 @@
/*
* This library is developed for Dabble app. https://thestempedia.com/product/dabble/
* It includes modulewise sublibraries as per modules present in
* Dabble app.
* Version 1.5.1
*
* This library structure is derived from OneSheeld Library.
*
* This is licensed under GNU GPL V3 [http://www.gnu.org/licenses/gpl.txt].
* Written by Dhrupal R Shah for ESP32, Agilo Research Pvt. Ltd
* Created on: April 10, 2019
* Updated on: 20190610
* Contact: support@thestempedia.com
* Copyright (c) 2018 Agilo Research Pvt. Ltd. All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef DabbleESP32_h
#define DabbleESP32_h
#include "Stream.h"
#include <Arduino.h>
#include "esp32BLEUtilities.h"
#include "ModuleIds.h"
#include "ModuleSelection.h"
#include "ModuleIncludes.h"
#include "ModuleParent.h"
#include "ModuleInstantiation.h"
//#include "InternetModule.h"
//#include "HttpResponse.h"
//#include "HttpRequest.h"
#define ONE_SECOND 1000
//Start and End of packet sent
#define START_OF_FRAME 0xFF
#define END_OF_FRAME 0x00
//Time between sending Frames
#define TIME_GAP 10UL
//#define DEBUG
//Output function ID's
#define CHECK_CONNECTION 0x01
#define BOARDID_REQUEST 0x03
#define SEND_LIBRARY_VERSION 0x01
#define CALLBACK_ENTERED 0x03
#define CALLBACK_EXITED 0x04
#define LIBRARY_TESTING_RESPONSE 0x05
//Input function ID's
//Checking Bluetooth connection
#define CONNECTION_CHECK_FUNCTION 0x01
#define DISCONNECTION_CHECK_FUNCTION 0x02
//#define LIBRARY_VERSION_REQUEST 0x03
//#define LIBRARY_TESTING_REQUEST 0x05
//Number of Module
#define MODULE_NO 18
extern bool callBackForDataLogger;
extern void (*dataLoggerCallBack)(void);
//Class for Datalength and Data
class FunctionArg
{
private:
byte length;
byte * data;
bool saveData;
public:
FunctionArg(int l ,byte * d, bool _saveData=false)
{
saveData=_saveData;
length=(l>0xff)?0xff:l;
if(saveData)
{
data=(byte *)malloc(sizeof(byte)*length);
memcpy(data,d,length);
}
else
{
data=d;
}
}
byte getLength()
{
return length;
}
byte * getData()
{
return data;
}
~FunctionArg()
{
if(saveData)free(data);
}
};
union FloatUnion{
float number;
byte floatBytes[sizeof(float)];
};
class DabbleClass
{
public:
DabbleClass();
//Blocking function
void waitForAppConnection();
//Check connection
bool isAppConnected();
void setOnAppConnected(void (*)(bool));
//rx,tx pins for software
uint8_t pin_rx,pin_tx;
//Getters
byte getModuleId();
byte getFunctionId();
byte getArgumentNo();
byte getScreenId();
byte readModuleId();
byte getArgumentLength(byte x);
byte * getArgumentData(byte );
void convertFloatToBytes(float , byte *);
float convertBytesToFloat(byte * );
//Processing Incomming Frames
void processInput();
void appWrite(byte command);
void begin(std::string bleName);
//Adding objects in array
static void addToModulesArray(ModuleParent *);
// #ifdef INTERNET_MODULE
//static void addToUnSentRequestsArray(HttpRequest *);
// #endif
static bool isInitialized();
static bool isSoftwareSerial();
//Frame Sender
void sendModuleFrame(byte , byte ,byte , byte , ...);
void sendModuleFrame(byte , byte , byte , byte , FunctionArg ** );
void setOnNewModuleFrame(void (*)(byte, byte, byte, byte *,byte **));
void setOnNewSerialData(void (*)(byte));
//PulseWidthModulation Getter
unsigned char analogRead(int );
void delay(unsigned long);
bool isCallbacksInterruptsSet();
void enableCallbacksInterrupts();
void disableCallbacksInterrupts();
byte getVerificationByte();
private:
//Reserve Variables
bool isArgumentsNumberMalloced;
bool isArgumentLengthMalloced;
bool isDabbleConnected;
bool isAppConnectionCallBack;
bool isModuleFrameCallback;
bool isSerialDataCallback;
bool dontDelay;
static bool isFirstFrame;
bool framestart;
static bool inACallback;
static bool callbacksInterrupts;
//Data bytes
byte numberOfDataMalloced;
byte Module;
byte verificationByte;
byte functions;
byte counter;
byte screenId;
byte readModuleID;
byte argumentcounter;
byte datalengthcounter;
byte argumentnumber;
byte argumentsize;
byte **arguments;
byte *argumentL;
byte endFrame;
//Module Counter
static byte ModulesCounter;
//Requests Counter
static byte requestsCounter;
//Is constructor called
static bool isInit;
static bool isSws;
//Checker variable
static unsigned long lastTimeFrameSent;
static unsigned long argumentDataBytesTimeReceived;
//Array of pointers to Parents
static ModuleParent * ModulesArray[MODULE_NO];
// #ifdef INTERNET_MODULE
//Array of pointers to un sent requests
//static HttpRequest ** requestsArray;
// #endif
//Send Incomming Data to Modules
void sendToModules();
//void begin(long baudRate);
void init();
void freeMemoryAllocated();
void processFrame();
void (*isAppConnectedCallBack)(bool);
void (*ModuleFrameCallback)(byte, byte, byte, byte *,byte **);
void (*serialDataCallback)(byte);
void enteringACallback();
void exitingACallback();
bool isInACallback();
void processInput(int);
friend class ModuleParent;
};
//Extern Object
extern DabbleClass Dabble;
#endif

View File

@ -0,0 +1,248 @@
#define FROM_DABBLE_LIBRARY
#include "DabbleESP32.h"
#include "DabbleInputs.h"
DabbleInputs::DabbleInputs() : ModuleParent(EVIVEINTERFACES_ID)
{
}
uint16_t DabbleInputs::getvalue_Pot1()
{
return uint16_t(data_1 << 8) + uint16_t (data_2);
}
uint16_t DabbleInputs::getvalue_Pot2()
{
return uint16_t(data_3 << 8) + uint16_t (data_4);
}
uint8_t DabbleInputs::getStatus_SlideSwitch1()
{
if((data_5 & 0x04) == 0x04)
{
state_ss1 =2;
}
else if((data_5 & 0x02) == 0x02)
{
state_ss1 =0;
}
else if((data_5 & 0x01) == 0x01)
{
state_ss1 =1;
}
return state_ss1;
}
uint8_t DabbleInputs::getStatus_SlideSwitch2()
{
if((data_5 & 0x20) == 0x20)
{
state_ss2=2;
}
else if((data_5&0x10) == 0x10)
{
state_ss2=0;
}
else if((data_5&0x08) == 0x08)
{
state_ss2=1;
}
return state_ss2;
}
bool DabbleInputs::getStatus_TactileSwitch1()
{
return ((data_5 & 0x40) == 0x40);
}
bool DabbleInputs::getStatus_TactileSwitch2()
{
return ((data_5 & 0x80) == 0x80);
}
uint16_t DabbleInputs::getPot1Value()
{
return uint16_t(data_1 << 8) + uint16_t (data_2);
}
uint16_t DabbleInputs::getPot2Value()
{
return uint16_t(data_3 << 8) + uint16_t (data_4);
}
uint8_t DabbleInputs::getSlideSwitch1Value()
{
if((data_5 & 0x04) == 0x04)
{
state_ss1 =2;
}
else if((data_5 & 0x02) == 0x02)
{
state_ss1 =0;
}
else if((data_5 & 0x01) == 0x01)
{
state_ss1 =1;
}
return state_ss1;
}
uint8_t DabbleInputs::getSlideSwitch2Value()
{
if((data_5 & 0x20) == 0x20)
{
state_ss2=2;
}
else if((data_5&0x10) == 0x10)
{
state_ss2=0;
}
else if((data_5&0x08) == 0x08)
{
state_ss2=1;
}
return state_ss2;
}
bool DabbleInputs::getTactileSwitch1Value()
{
return ((data_5 & 0x40) == 0x40);
}
bool DabbleInputs::getTactileSwitch2Value()
{
return ((data_5 & 0x80) == 0x80);
}
bool DabbleInputs::getSlideSwitchStatus(uint8_t SS,uint8_t dir)
{
if(SS == 1 && dir == 2) //SS1 left
{
if((data_5 & 0x01)==0x01)
{
return 1;
}
else
{
return 0;
}
}
else if(SS == 1 && dir == 3) //SS1 right
{
if((data_5&0x04) == 0x04)
{
return 1;
}
else
{
return 0;
}
}
else if(SS == 1 && dir == 1) //SS1 Off
{
if((data_5&0x02) == 0x02)
{
return 1;
}
else
{
return 0;
}
}
else if(SS == 2 && dir == 2) //SS2 left
{
if((data_5&0x08) == 0x08)
{
return 1;
}
else
{
return 0;
}
}
else if(SS == 2 && dir == 3) //SS2 right
{
if((data_5&0x20) == 0x20)
{
return 1;
}
else
{
return 0;
}
}
else if(SS == 2 && dir == 1) //SS2 Off
{
if((data_5&0x10) == 0x10)
{
return 1;
}
else
{
return 0;
}
}
}
bool DabbleInputs::getTactileSwitchStatus(uint8_t TS)
{
if(TS == 1)
{
if((data_5 & 0x40) == 0x40)
return 1;
else
return 0;
}
else if(TS == 2)
{
if((data_5 & 0x80) == 0x80)
return 1;
else
return 0;
}
}
int DabbleInputs::getPotValue(uint8_t Pot)
{
if(Pot == 1)
{
return uint16_t(data_1 << 8) + uint16_t (data_2);
}
else if(Pot == 2)
{
return uint16_t(data_3 << 8) + uint16_t (data_4);
}
}
void DabbleInputs::processData()
{
/*#ifdef DEBUG
Serial.println("DabbleInputs:processData");
#endif*/
//Checking Function-ID
byte functionId =getDabbleInstance().getFunctionId();
if(functionId == Potentiometer_1)
{
data_1=getDabbleInstance().getArgumentData(0)[0];
data_2=getDabbleInstance().getArgumentData(0)[1];
}
else if(functionId == Potentiometer_2)
{
data_3=getDabbleInstance().getArgumentData(0)[0];
data_4=getDabbleInstance().getArgumentData(0)[1];
}
else if(functionId == Switches)
{
data_5=getDabbleInstance().getArgumentData(0)[0];
}
}

View File

@ -0,0 +1,66 @@
#ifndef DabbleInputs_h
#define DabbleInputs_h
#include "ModuleParent.h"
#define Potentiometer_1 0x01
#define Potentiometer_2 0x02
#define Switches 0x03
//#define DEBUG
class DabbleInputs: public ModuleParent
{
public:
//Constructor
DabbleInputs();
//Checker Functions
uint16_t getPot1Value();
uint16_t getPot2Value();
uint8_t getSlideSwitch1Value();
uint8_t getSlideSwitch2Value();
bool getTactileSwitch1Value();
bool getTactileSwitch2Value();
uint16_t getvalue_Pot1();
uint16_t getvalue_Pot2();
uint8_t getStatus_SlideSwitch1();
uint8_t getStatus_SlideSwitch2();
bool getStatus_TactileSwitch1();
bool getStatus_TactileSwitch2();
bool getSlideSwitchStatus(uint8_t SS,uint8_t dir); //1 2 SS1 left //2 2 SS2 left
//1 3 SS1 right //2 3 SS2 right
//1 1 SS1 Off //2 1 SS2 Off
bool getTactileSwitchStatus(uint8_t TS); //1 TS1 2 TS2
int getPotValue(uint8_t Pot);
public:
byte functionId;
byte data_1=0;
byte data_2=0;
byte data_3=0;
byte data_4=0;
byte data_5=0;
uint8_t state_ss1;
uint8_t state_ss2;
private:
void processData();
};
//Extern Object
extern DabbleInputs Inputs;
#endif

View File

@ -0,0 +1,86 @@
#define FROM_DABBLE_LIBRARY
#include "DabbleESP32.h"
#include "DabblePrint.h"
//Constructor
PrintClass::PrintClass(byte shid,byte writefnid, byte printfnid)
{
ModuleId=shid;
print_fn_id=printfnid;
write_fn_id=writefnid;
}
//Write character
void PrintClass::write(char data)
{
Dabble.sendModuleFrame(ModuleId,0,write_fn_id,1,new FunctionArg(1,(byte *)&data));
}
//Print character
void PrintClass::print(char data)
{
Dabble.sendModuleFrame(ModuleId,0,print_fn_id,1,new FunctionArg(1,(byte *)&data));
}
//Print integers
void PrintClass::print(int data)
{
char stringPointer[7];
snprintf(stringPointer,7,"%d",data);
Dabble.sendModuleFrame(ModuleId,0,print_fn_id,1,new FunctionArg(strlen(stringPointer),(byte *)stringPointer));
}
//Print unsigned integers
void PrintClass::print(unsigned int data)
{
char stringPointer[6];
snprintf(stringPointer,6,"%d",data);
Dabble.sendModuleFrame(ModuleId,0,print_fn_id,1,new FunctionArg(strlen(stringPointer),(byte *)stringPointer));
}
//Print long integers
void PrintClass::print(long data)
{
char stringPointer[12];
snprintf(stringPointer,12,"%ld",data);
Dabble.sendModuleFrame(ModuleId,0,print_fn_id,1,new FunctionArg(strlen(stringPointer),(byte *)stringPointer));
}
//Print unsigned long integers
void PrintClass::print(unsigned long data)
{
char stringPointer[11];
snprintf(stringPointer,11,"%lu",data);
Dabble.sendModuleFrame(ModuleId,0,print_fn_id,1,new FunctionArg(strlen(stringPointer),(byte *)stringPointer));
}
//Print string
void PrintClass::print(const char * stringData)
{
//Serial.println("Print String");
//Check length of string
int stringDataLength = strlen(stringData);
#ifdef DEBUG
Serial.println(stringDataLength);
#endif
if(!stringDataLength) return;
Dabble.sendModuleFrame(ModuleId,0,print_fn_id,1,new FunctionArg(stringDataLength,(byte*)stringData));
}
void PrintClass::print(String stringData)
{
print(&stringData[0]);
}
//Print double
//Unsupported by Intel Galileo board and Arduino Due
#if !defined(ARDUINO_LINUX) && !defined(SAM3X8)
void PrintClass::print(double data , int precesion)
{
char buffer[32]={'\0'};
dtostrf(data,1,precesion,buffer);
Dabble.sendModuleFrame(ModuleId,0,print_fn_id,1,new FunctionArg(strlen(buffer),(byte *) buffer));
}
#endif

View File

@ -0,0 +1,35 @@
#ifndef PrintClass_h
#define PrintClass_h
//Defining decimal
#define DEC 10
class PrintClass
{
public:
PrintClass(byte, byte, byte);
//Write
void write(char);
//Printing functions
void print(char);
void print(int);
void print(unsigned int);
void print(long);
void print(unsigned long);
void print(const char *);
void print(String );
//Unsupported by Intel Galileo board and Arduino Due
#if !defined(ARDUINO_LINUX) && !defined(SAM3X8)
void print(double ,int = 3 );
#endif
private:
//Reserve variables for function ID's
byte print_fn_id;
byte write_fn_id;
//Reserve variable for the Module ID
byte ModuleId;
};
extern PrintClass PinStatus;
#endif

View File

@ -0,0 +1,107 @@
#define FROM_DABBLE_LIBRARY
#include "DabbleESP32.h"
#include "DabblePrintln.h"
//Constructor
PrintlnClass::PrintlnClass(byte shid,byte writefnid, byte printfnid):PrintClass(shid,writefnid,printfnid)
{
}
//Print newline
void PrintlnClass::println()
{
char buffer[3];
buffer[0]='\r';
buffer[1]='\n';
buffer[2]='\0';
print(buffer);
}
//Print character with newline
void PrintlnClass::println(char data)
{
char buffer[4];
buffer[0]=data;
buffer[1]='\r';
buffer[2]='\n';
buffer[3]='\0';
print(buffer);
}
//Print integers with newline
void PrintlnClass::println(int data)
{
char stringPointer[10];
snprintf(stringPointer,9,"%d",data);
strcat(stringPointer,"\r\n");
print(stringPointer);
#ifdef DEBUG
Serial.println(data);
Serial.println(stringPointer);
#endif
}
//Print unsigned integers with newline
void PrintlnClass::println(unsigned int data)
{
char stringPointer[9];
snprintf(stringPointer,8,"%d",data);
strcat(stringPointer,"\r\n");
print(stringPointer);
}
//Print long with newline
void PrintlnClass::println(long data)
{
char stringPointer[15];
snprintf(stringPointer,14,"%ld",data);
strcat(stringPointer,"\r\n");
print(stringPointer);
}
//Print unsigned long with newline
void PrintlnClass::println(unsigned long data)
{
char stringPointer[14];
snprintf(stringPointer,13,"%lu",data);
strcat(stringPointer,"\r\n");
print(stringPointer);
}
//Print string with newline
void PrintlnClass::println(const char * stringData)
{
char stringNewLine[strlen(stringData)+3];
stringNewLine[0]='\0';
strcat(stringNewLine,stringData);
strcat(stringNewLine,"\r\n");
print(stringNewLine);
}
//Support strings
void PrintlnClass::println(String stringData)
{
println(&stringData[0]);
}
//Unsupported by Intel Galileo board and Arduino Due
#if !defined(ARDUINO_LINUX) && !defined(SAM3X8)
void PrintlnClass::println(double data, int precesion)
{
int i=0;
char buffer[32]={'\0'};
dtostrf(data,1,precesion,buffer);
while(buffer[i]!='\0' && i<32)i++;
if(i+2>32)return;
buffer[i]='\r';
buffer[i+1]='\n';
buffer[i+2]='\0';
print(buffer);
}
#endif

View File

@ -0,0 +1,27 @@
#ifndef PrintlnClass_h
#define PrintlnClass_h
#include "DabblePrint.h"
class PrintlnClass: public PrintClass
{
public:
PrintlnClass(byte, byte, byte);
//Printing in new line
void println();
void println(char);
void println(int);
void println(unsigned int);
void println(long);
void println(unsigned long);
void println(const char *);
void println(String);
//Unsupported by Intel Galileo board and Arduino Due
#if !defined(ARDUINO_LINUX) && !defined(SAM3X8)
void println(double , int = 3);
#endif
};
#endif

View File

@ -0,0 +1,231 @@
#define FROM_DABBLE_LIBRARY
#include "DabbleESP32.h"
#include "DataLoggerModule.h"
uint8_t columnNumber=0;
String *tempColName = NULL;
DataLoggerModule::DataLoggerModule():ModuleParent(DATALOGGER_ID)
{}
void DataLoggerModule::sendSettings(void(*function)(void))
{
callBackForDataLogger = true;
dataLoggerCallBack = function;
}
void DataLoggerModule::createFile(String FileName)
{
columnNumber=0;
Dabble.sendModuleFrame(DATALOGGER_ID,0,FILENAME,1,new FunctionArg(FileName.length(),(byte *)&FileName[0]));
}
void DataLoggerModule::createColumn(String colName)
{
//Process to store FileNames starts
if(columnNumber != 0)
{
if(columnNumber != 1)
delete [] tempColName;
tempColName = new String[columnNumber];
}
for(int i=0;i<columnNumber;i++)
{
tempColName[i] = columnName[i];
}
if(columnNumber !=0 )
{
delete[] columnName;
}
columnName = new String[columnNumber+1]; //+1 since number of columns start from 0;
for(int i = 0;i < columnNumber;i++)
{
columnName[i] = tempColName[i];
}
columnName[columnNumber] = colName;
#ifdef DEBUG
for(int i=0;i<(columnNumber+1);i++)
{
Serial.println(columnName[i]);
}
#endif
//end
uint8_t a = columnNumber+1;
String sendColumnName = columnName[columnNumber];
Dabble.sendModuleFrame(DATALOGGER_ID,0,COLUMNNAME,2,new FunctionArg(1,&a),new FunctionArg(sendColumnName.length(),(byte *)&sendColumnName[0]));
columnNumber++;
}
void DataLoggerModule::fileConfig(uint8_t type, String Name)
{
if(type == 1)
{
createFile(Name);
}
else if(type == 2)
{
createColumn(Name);
}
}
void DataLoggerModule::send(String col,float data)
{
byte columnFlag=0;
byte floatData[4];
Dabble.convertFloatToBytes(data,floatData);
for(int i =0;i<columnNumber;i++)
{
if(col == columnName[i])
{
columnFlag = i+1;
#ifdef DEBUG
//Serial.println(columnFlag);
#endif
break;
}
}
if(columnFlag == 0)
{
#ifdef DEBUG
//Serial.println("No match");
#endif
return;
}
Dabble.sendModuleFrame(DATALOGGER_ID,0,DATATYPE_FLOAT,2,new FunctionArg(1,&columnFlag),new FunctionArg(sizeof(float),floatData));
}
void DataLoggerModule::send(String col,String data)
{
byte columnFlag=0;
for(int i =0;i<columnNumber;i++)
{
if(col == columnName[i])
{
columnFlag = i+1;
#ifdef DEBUG
//Serial.println(columnFlag);
#endif
break;
}
}
if(columnFlag == 0)
{
return;
}
Dabble.sendModuleFrame(DATALOGGER_ID,0,DATATYPE_CHAR,2,new FunctionArg(1,&columnFlag),new FunctionArg(data.length(),(byte *)&data[0]));
}
void DataLoggerModule::stop()
{
Dabble.sendModuleFrame(DATALOGGER_ID,0,CLOSEFILE,0);
}
/*void DataLoggerModule::createFile(String FileName,int count,...)
{
columnNumber = count;
va_list colName;
va_start(colName, count);
char *str;
columnName = new String[count];
for ( int i = 0; i < count; i++ ) // do "count" times
{
str = va_arg( colName, char* );
columnName[i] = "";
while (*str != '\0')
{
columnName[i] = String(columnName[i] + *str);
//columnName[i] = String(columnName[i] + *str);
str++;
}
}
va_end(colName);
//columnName=&columnName[0];
#ifdef DEBUG
for(int i = 0;i<count;i++)
{
//Serial.print(i);
//Serial.print(" ");
//Serial.println(columnName[i]);
}
#endif
//Serial.println();
byte fileNameLength = FileName.length();
Dabble.sendModuleFrame(DATALOGGER_ID,0,FILENAME,1,new FunctionArg(fileNameLength,&FileName[0]));
for(uint8_t i=0;i<count;i++)
{
byte a = i+1;
byte columnNameLength = columnName[i].length();
Dabble.sendModuleFrame(DATALOGGER_ID,0,COLUMNNAME,2,new FunctionArg(1,&a),new FunctionArg(columnNameLength,&columnName[i][0]));
}
}*/
/*void DataLoggerModule::send(String col,int data)
{
byte columnFlag=0;
for(int i =0;i<columnNumber;i++)
{
if(col == columnName[i])
{
columnFlag = i+1;
//Serial.println(columnFlag);
break;
}
}
if(columnFlag == 0)
{
return;
}
byte a[2];
a[0] = byte(data>>8);
a[1] = byte(data);
//Serial.print(a[0],BIN);
//Serial.print(" ");
//Serial.print(a[1],BIN);
//Serial.print(" ");
//Serial.println(data,BIN);
Dabble.sendModuleFrame(DATALOGGER_ID,0,DATATYPE_INT,2,new FunctionArg(1,&columnFlag),new FunctionArg(sizeof(int),a));
}*/
/*void send(int count,...)
{
String tempColName = "";
byte columnFlag = 0;
va_list columData;
va_start(colData, count);
for(int i=0;i<count;i++)
{
if(i%2 == 0)
{
char *tempData;
tempData = va_arg( colName, char* );
while(*tempData != '\0')
{
tempColName = String(tempColName + *tempData);
}
for(int i =0;i<columnNumber;i++)
{
if(col == columnName[i])
{
columnFlag = i+1;
//Serial.println(columnFlag);
break;
}
}
if(columnFlag == 0)
{
return;
}
}
if(i%2 == 1)
{
}
}
va_end(colData);
}*/

View File

@ -0,0 +1,32 @@
#ifndef DataLoggerModule_H_
#define DataLoggerModule_H_
#include "ModuleParent.h"
//functionId
#define FILENAME 0x01
#define COLUMNNAME 0x02
#define CLOSEFILE 0x03
#define DATATYPE_CHAR 0x04
#define DATATYPE_INT 0x05
#define DATATYPE_FLOAT 0x06
class DataLoggerModule:public ModuleParent
{
public:
DataLoggerModule();
void createFile(String);
//void createFile(String,int,...); //FileName, number of columns,column names
void createColumn(String colName);
void send(String,float);
void send(String,String);
void sendSettings(void(*)(void));
//void send(String,char);
//void send(int,...);
void stop();
//PictoBlox
void fileConfig(uint8_t,String);
String *columnName =NULL;
};
extern DataLoggerModule DataLogger;
#endif

View File

@ -0,0 +1,268 @@
#define FROM_DABBLE_LIBRARY
#include "DabbleESP32.h"
#include "GamePadModule.h"
#define PI 3.14159
//Class Constructor
GamePadModule::GamePadModule() : ModuleParent(GAMEPAD_ID)
{
value =0;
value0=0;
//isCallBackAssigned=false;
}
//Up ArrowChecker
bool GamePadModule::isUpPressed()
{
if(mode == 0)
return !!(value & (1<<UP_BIT));
else
return 0;
}
//Down Arrow Checker
bool GamePadModule::isDownPressed()
{ if(mode == 0)
return !!(value & (1<<DOWN_BIT));
else
return 0;
}
//Left Arrow Checker
bool GamePadModule::isLeftPressed()
{ if(mode == 0)
return !!(value & (1<<LEFT_BIT));
else
return 0;
}
//Right Arrow Checker
bool GamePadModule::isRightPressed()
{ if(mode == 0)
return !!(value & (1<<RIGHT_BIT));
else
return 0;
}
//Orange Button Checker
bool GamePadModule::isStartPressed()
{
return !!(value0 & (1<<START_BIT));
}
//Red Button Checker
bool GamePadModule::isSelectPressed()
{
return !!(value0 & (1<<SELECT_BIT));
}
//Green Button Checker
bool GamePadModule::isTrianglePressed()
{
return !!(value0 & (1<<TRIANGLE_BIT));
}
//Blue Button Checker
bool GamePadModule::isCirclePressed()
{
return !!(value0 & (1<<CIRCLE_BIT));
}
bool GamePadModule::isCrossPressed()
{
return !!(value0 & (1<<CROSS_BIT));
}
bool GamePadModule::isSquarePressed()
{
return !!(value0 & (1<<SQUARE_BIT));
}
bool GamePadModule::isPressed(uint8_t a)
{
if(a == 0)
{
if(mode == 0)
return !!(value & (1<<UP_BIT));
else
return 0;
}
else if(a==1)
{
if(mode == 0)
return !!(value & (1<<DOWN_BIT));
else
return 0;
}
else if(a==2)
{
if(mode == 0)
return !!(value & (1<<LEFT_BIT));
else
return 0;
}
else if(a==3)
{
if(mode == 0)
return !!(value & (1<<RIGHT_BIT));
else
return 0;
}
else if(a==4)
{
return !!(value0 & (1<<START_BIT));
}
else if(a==5)
{
return !!(value0 & (1<<SELECT_BIT));
}
else if(a==6)
{
return !!(value0 & (1<<TRIANGLE_BIT));
}
else if(a==7)
{
return !!(value0 & (1<<CIRCLE_BIT));
}
else if(a==8)
{
return !!(value0 & (1<<CROSS_BIT));
}
else if(a==9)
{
return !!(value0 & (1<<SQUARE_BIT));
}
}
//GamePad Input Data Processing
void GamePadModule::processData()
{
#ifdef DEBUG
Serial.println("GamePad:processData");
#endif
//Checking Function-ID
byte functionId =getDabbleInstance().getFunctionId();
if(functionId==GAMEPAD_DIGITAL)
{
mode=0;
value0=getDabbleInstance().getArgumentData(0)[0]; //
#ifdef DEBUG
Serial.println(value0,BIN);
#endif
value=getDabbleInstance().getArgumentData(0)[1];
#ifdef DEBUG
Serial.println(value,BIN);
#endif
//Users Function Invoked
/*if(isCallBackAssigned && !isInACallback())
{
enteringACallback();
(*buttonChangeCallBack)(!!(value & (1<<UP_BIT)), !!(value & (1<<DOWN_BIT)),
!!(value & (1<<LEFT_BIT)), !!(value & (1<<RIGHT_BIT)),
!!(value0 & (1<<START_BIT)), !!(value0 & (1<<SELECT_BIT)),
!!(value0 & (1<<TRIANGLE_BIT)), !!(value0 & (1<<CIRCLE_BIT)));
exitingACallback();
}*/
}
else if(functionId == GAMEPAD_ANALOG)
{
mode=1;
value0=getDabbleInstance().getArgumentData(0)[0]; //
#ifdef DEBUG
Serial.println(value0,BIN);
#endif
value=getDabbleInstance().getArgumentData(0)[1];
#ifdef DEBUG
Serial.println(value,BIN);
#endif
}
else if(functionId == GAMEPAD_ACCL)
{
mode=1;
value0=getDabbleInstance().getArgumentData(0)[0]; //
#ifdef DEBUG
Serial.println(value0,BIN);
#endif
value=getDabbleInstance().getArgumentData(0)[1];
#ifdef DEBUG
Serial.println(value,BIN);
#endif
}
}
float GamePadModule::getJoystickData(uint8_t b)
{
uint16_t angle=((value >> 3)*15);
uint8_t radius=value&0x07;
float x_value= float(radius*(float(cos(float(angle*PI/180)))));
float y_value= float(radius*(float(sin(float(angle*PI/180)))));
if(b == 0)
{
return angle;
}
else if(b==1)
{
return radius;
}
else if(b==2)
{
return x_value;
}
else if(b==3)
{
return y_value;
}
}
uint16_t GamePadModule::getAngle()
{
if(mode == 1)
return ((value >> 3)*15);
else
return 0;
}
uint8_t GamePadModule::getRadius()
{
if(mode == 1)
return (value&0x07);
else
return 0;
}
float GamePadModule::getXaxisData()
{
uint16_t angle=((value >> 3)*15);
uint8_t radius=value&0x07;
float x_value= float(radius*(float(cos(float(angle*PI/180)))));
return x_value;
}
float GamePadModule::getYaxisData()
{
uint16_t angle=((value >> 3)*15);
uint8_t radius=value&0x07;
float y_value= float(radius*(float(sin(float(angle*PI/180)))));
return y_value;
}
float GamePadModule::getx_axis()
{
uint16_t angle=((value >> 3)*15);
uint8_t radius=value&0x07;
float x_value= float(radius*(float(cos(float(angle*PI/180)))));
return x_value;
}
float GamePadModule::gety_axis()
{
uint16_t angle=((value >> 3)*15);
uint8_t radius=value&0x07;
float y_value= float(radius*(float(sin(float(angle*PI/180)))));
return y_value;
}

View File

@ -0,0 +1,80 @@
#ifndef GamePadModule_h
#define GamePadModule_h
#include "ModuleParent.h"
//Input Function ID
#define GAMEPAD_DIGITAL 0x01
#define GAMEPAD_ANALOG 0x02
#define GAMEPAD_ACCL 0x03
//GamePad Bit Reference
//Byte 1
#define START_BIT 0
#define SELECT_BIT 1
#define TRIANGLE_BIT 2
#define CIRCLE_BIT 3
#define CROSS_BIT 4
#define SQUARE_BIT 5
//Byte 2 in case of Digital Mode GamePad
#define UP_BIT 0
#define DOWN_BIT 1
#define LEFT_BIT 2
#define RIGHT_BIT 3
//Byte 2 in case of Analog/Accelerometer Mode GamePad
//XXXXXYYY = XXXXX(*15) is angle in radians, YYY is radius
class GamePadModule : public ModuleParent
{
public:
//Constructor
GamePadModule();
//Arduino
//Checker Functions
bool isStartPressed();
bool isSelectPressed();
bool isTrianglePressed();
bool isCirclePressed();
bool isCrossPressed();
bool isSquarePressed();
bool isUpPressed();
bool isDownPressed();
bool isLeftPressed();
bool isRightPressed();
uint16_t getAngle();
uint8_t getRadius();
float getXaxisData();
float getYaxisData();
float getx_axis();
float gety_axis();
//Pictoblox
bool isPressed(uint8_t a);
float getJoystickData(uint8_t b);
//setOnChange for Users Function
/* void setOnButtonChange(void (*)(unsigned char , unsigned char ,
unsigned char , unsigned char ,
unsigned char , unsigned char ,
unsigned char , unsigned char ));
*/private:
//Reserve Variables
bool mode; //mode=0 for gamepad , mode = 1 for joystick
byte value;
byte value0;
//bool isCallBackAssigned;
//Process Input Data
void processData();
/*void (*buttonChangeCallBack)(unsigned char , unsigned char ,
unsigned char , unsigned char ,
unsigned char ,unsigned char ,
unsigned char ,unsigned char );*/
};
//Extern Object
extern GamePadModule GamePad;
#endif

View File

@ -0,0 +1,16 @@
#define INCLUDE_DABBLEINPUTS_MODULE
#define INCLUDE_TERMINAL_MODULE
#define INCLUDE_INTERNET_MODULE
#define INCLUDE_MOTORCONTROL_MODULE
#define INCLUDE_GAMEPAD_MODULE
#define INCLUDE_PINMONITOR_MODULE
#define INCLUDE_SENSOR_MODULE
#define INCLUDE_CAMERA_MODULE
#define INCLUDE_LEDCONTROL_MODULE
#define INCLUDE_COLORDETECTOR_MODULE
#define INCLUDE_DATALOGGER_MODULE
#define INCLUDE_SMS_MODULE
#define INCLUDE_NOTIFICATION_MODULE
#define INCLUDE_MUSIC_MODULE
#define INCLUDE_ROBOTICARM_MODULE
#define INCLUDE_HOMEAUTOMATION_MODULE

View File

@ -0,0 +1,517 @@
#define FROM_DABBLE_LIBRARY
#include "DabbleESP32.h"
#include "InternetModule.h"
//Constructor
InternetModule::InternetModule():ModuleParent(INTERNET_ID)
{}
/*//Read from Android
char InternetModule::read()
{
if(buffer.remain()<=0)return -1;
return buffer.pop();
return 0;
}
//Flush buffer contents
void InternetModule::flush()
{
while(read()!=-1);
}
//Check Data avialable in Buffer
int InternetModule::available()
{
return buffer.remain();
}
//Read bytes from Buffer
int InternetModule::readBytes(char *arr, int length)
{
int count = 0;
while (count < length) {
int c = read();
if (c < 0) break;
*arr++ = (char)c;
count++;
}
return count;
}
*/
//Terminal Incomming Data processing
void InternetModule::processData()
{
byte functionID = getDabbleInstance().getFunctionId();
byte dataLength = getDabbleInstance().getArgumentLength(0);
byte dataLines = getDabbleInstance().getArgumentNo();
/*Serial.print("In processInput");
Serial.println(functionID);
Serial.println(dataLength);*/
if(functionID == HTTP_RESPONSE && successState == 1 )
{
successState = 0;
//Serial.println("Response");
mainString = "";
int counter = 0;
for(int i = 0;i< dataLines; i++)
{
for (int j=0; j<dataLength; j++)
{
//Serial.print("counter= " + String(counter) + " ");
//Serial.println(char (getDabbleInstance().getArgumentData(i)[j]));
mainString = mainString + char(getDabbleInstance().getArgumentData(i)[j]);
counter++;
}
}
Serial.println(mainString);
}
if(functionID == HTTP_SUCCESS)
{
successState = 1;
#ifdef DEBUG
//Serial.println("Success");
//Serial.println(getDabbleInstance().getArgumentData(0)[0]);
#endif
}
}
void InternetModule::sendGETRequest(String Urladd)
{
Dabble.sendModuleFrame(INTERNET_ID,0,HTTP_GET,1,new FunctionArg(Urladd.length(),(byte *)&Urladd[0]));
}
void InternetModule::updateChannelFeed(String KEY,int noOfData, int value1, int value2, int value3, int value4, int value5, int value6, int value7, int value8)
{
String channelFeedUrl = "";
String baseUrl = "https://api.thingspeak.com/update?api_key=";
channelFeedUrl = baseUrl + KEY;
if(noOfData == 1)
{
channelFeedUrl = channelFeedUrl + "&field1=" + String(value1);
#ifdef DEBUG
Serial.println(channelFeedUrl);
#endif
}
if(noOfData == 2)
{
channelFeedUrl = channelFeedUrl + "&field1=" + String(value1);
channelFeedUrl = channelFeedUrl + "&field2=" + String(value2);
#ifdef DEBUG
Serial.println(channelFeedUrl);
#endif
}
if(noOfData == 3)
{
channelFeedUrl = channelFeedUrl + "&field1=" + String(value1);
channelFeedUrl = channelFeedUrl + "&field2=" + String(value2);
channelFeedUrl = channelFeedUrl + "&field3=" + String(value3);
#ifdef DEBUG
Serial.println(channelFeedUrl);
#endif
}
if(noOfData == 4)
{
channelFeedUrl = channelFeedUrl + "&field1=" + String(value1);
channelFeedUrl = channelFeedUrl + "&field2=" + String(value2);
channelFeedUrl = channelFeedUrl + "&field3=" + String(value3);
channelFeedUrl = channelFeedUrl + "&field4=" + String(value4);
#ifdef DEBUG
Serial.println(channelFeedUrl);
#endif
}
if(noOfData == 5)
{
channelFeedUrl = channelFeedUrl + "&field1=" + String(value1);
channelFeedUrl = channelFeedUrl + "&field2=" + String(value2);
channelFeedUrl = channelFeedUrl + "&field3=" + String(value3);
channelFeedUrl = channelFeedUrl + "&field4=" + String(value4);
channelFeedUrl = channelFeedUrl + "&field5=" + String(value5);
#ifdef DEBUG
Serial.println(channelFeedUrl);
#endif
}
if(noOfData == 6)
{
channelFeedUrl = channelFeedUrl + "&field1=" + String(value1);
channelFeedUrl = channelFeedUrl + "&field2=" + String(value2);
channelFeedUrl = channelFeedUrl + "&field3=" + String(value3);
channelFeedUrl = channelFeedUrl + "&field4=" + String(value4);
channelFeedUrl = channelFeedUrl + "&field5=" + String(value5);
channelFeedUrl = channelFeedUrl + "&field6=" + String(value6);
#ifdef DEBUG
Serial.println(channelFeedUrl);
#endif
}
if(noOfData == 7)
{
channelFeedUrl = channelFeedUrl + "&field1=" + String(value1);
channelFeedUrl = channelFeedUrl + "&field2=" + String(value2);
channelFeedUrl = channelFeedUrl + "&field3=" + String(value3);
channelFeedUrl = channelFeedUrl + "&field4=" + String(value4);
channelFeedUrl = channelFeedUrl + "&field5=" + String(value5);
channelFeedUrl = channelFeedUrl + "&field6=" + String(value6);
channelFeedUrl = channelFeedUrl + "&field7=" + String(value7);
#ifdef DEBUG
Serial.println(channelFeedUrl);
#endif
}
if(noOfData == 8)
{
channelFeedUrl = channelFeedUrl + "&field1=" + String(value1);
channelFeedUrl = channelFeedUrl + "&field2=" + String(value2);
channelFeedUrl = channelFeedUrl + "&field3=" + String(value3);
channelFeedUrl = channelFeedUrl + "&field4=" + String(value4);
channelFeedUrl = channelFeedUrl + "&field5=" + String(value5);
channelFeedUrl = channelFeedUrl + "&field6=" + String(value6);
channelFeedUrl = channelFeedUrl + "&field7=" + String(value7);
channelFeedUrl = channelFeedUrl + "&field8=" + String(value8);
#ifdef DEBUG
Serial.println(channelFeedUrl);
#endif
}
if(channelFeedUrl.length() < 256)
{
Dabble.sendModuleFrame(INTERNET_ID,0,HTTP_GET,1,new FunctionArg(channelFeedUrl.length(),(byte *)&channelFeedUrl[0]));
}
else
{
#ifdef DEBUG
Serial.println("Data too long");
#endif
}
}
void InternetModule::updateChannelField(String KEY, uint8_t fieldNumber,int data)
{
String channelFeedUrl = "";
String baseUrl = "https://api.thingspeak.com/update?api_key=";
channelFeedUrl = baseUrl + KEY;
channelFeedUrl = channelFeedUrl + "&field" + String(fieldNumber) + "=" + String(data);
//Serial.println(channelFeedUrl);
Dabble.sendModuleFrame(INTERNET_ID,0,HTTP_GET,1,new FunctionArg(channelFeedUrl.length(),(byte *)&channelFeedUrl[0]));
}
// https://api.thingspeak.com/channels/767508/fields/1.json?api_key=GHZVP14IXO9CINZO&results=2
float InternetModule::getFieldData(String KEY,uint8_t fieldNumber,long timeout)
{
String fieldDataUrl = "";
String baseUrl = "https://api.thingspeak.com/channels/767508/fields/";
fieldDataUrl = baseUrl + String(fieldNumber) + ".json?api_key=" + KEY + "&results=2";
/*#ifdef DEBUG
Serial.println(fieldDataUrl);
#endif*/
Dabble.sendModuleFrame(INTERNET_ID,0,HTTP_GET,1,new FunctionArg(fieldDataUrl.length(),(byte *)&fieldDataUrl[0]));
long lastTime =millis();
//String mainString = "";
Dabble.delay(10000);
//Serial.println(mainString);
int feedindex = mainString.indexOf("feeds");
//Serial.println("feedindex" + String(feedindex));
if(feedindex != -1)
{
int fieldindex = mainString.indexOf("field1", feedindex);
if(fieldindex != -1 && fieldNumber == 1){
float fieldValue1;
for (int k=9; k<100; k++){
String value1string = mainString.substring(fieldindex+9,fieldindex+k+1);
fieldValue1 = value1string.toFloat();
k++;
}
return fieldValue1;
}
fieldindex = mainString.indexOf("field2", feedindex);
Serial.println(fieldindex);
if(fieldindex != -1 && fieldNumber == 2){
float fieldValue2;
for (int k=9; k<100; k++){
String value1string = mainString.substring(fieldindex+9,fieldindex+k+1);
fieldValue2 = value1string.toFloat();
k++;
}
return fieldValue2;
}
fieldindex = mainString.indexOf("field3", feedindex);
if(fieldindex != -1 && fieldNumber == 3){
float fieldValue3;
for (int k=9; k<100; k++){
String value1string = mainString.substring(fieldindex+9,fieldindex+k+1);
fieldValue3 = value1string.toFloat();
k++;
}
return fieldValue3;
}
fieldindex = mainString.indexOf("field4", feedindex);
if(fieldindex != -1 && fieldNumber == 4){
float fieldValue4;
for (int k=9; k<100; k++){
String value1string = mainString.substring(fieldindex+9,fieldindex+k+1);
fieldValue4 = value1string.toFloat();
k++;
}
return fieldValue4;
}
fieldindex = mainString.indexOf("field5", feedindex);
if(fieldindex != -1 && fieldNumber == 5){
float fieldValue5;
for (int k=9; k<100; k++){
String value1string = mainString.substring(fieldindex+9,fieldindex+k+1);
fieldValue5 = value1string.toFloat();
k++;
}
return fieldValue5;
}
fieldindex = mainString.indexOf("field6", feedindex);
if(fieldindex != -1 && fieldNumber == 6){
float fieldValue6;
for (int k=9; k<100; k++){
String value1string = mainString.substring(fieldindex+9,fieldindex+k+1);
fieldValue6 = value1string.toFloat();
k++;
}
return fieldValue6;
}
fieldindex = mainString.indexOf("field7", feedindex);
if(fieldindex != -1 && fieldNumber == 7){
float fieldValue7;
for (int k=9; k<100; k++){
String value1string = mainString.substring(fieldindex+9,fieldindex+k+1);
fieldValue7 = value1string.toFloat();
k++;
}
return fieldValue7;
}
fieldindex = mainString.indexOf("field8", feedindex);
if(fieldindex != -1 && fieldNumber == 8){
float fieldValue8;
for (int k=9; k<100; k++){
String value1string = mainString.substring(fieldindex+9,fieldindex+k+1);
fieldValue8 = value1string.toFloat();
k++;
}
return fieldValue8;
}
}
else{
return -100;
}
}
void InternetModule::getWeatherData(String KEY, float lat, float lon)
{
String latString = "";
String longString = "";
String appId = "";
//"https:api.openweathermap.org/data/2.5/weather?lat={lat}&lon={lon}""
String weatherURL = "";
String baseUrl = "https://api.openweathermap.org/data/2.5/weather?";
latString = "lat=" + String(lat);
longString = "lon=" + String(lon);
appId = "appid=" + KEY;
weatherURL = baseUrl + latString + "&" + longString + "&" + appId ;
Serial.println(weatherURL);
Dabble.sendModuleFrame(INTERNET_ID,0,HTTP_GET,1,new FunctionArg(weatherURL.length(),(byte *)&weatherURL[0]));
Dabble.delay(10000);
Serial.println(mainString);
int fieldindex;
int feedindex;
String tester = String("\"");
Serial.println(mainString);
fieldindex = mainString.indexOf("lon");
if(fieldindex != -1){
for (int k=9; k<20; k++){
String value1string = mainString.substring(fieldindex+5,fieldindex+k+1);
longitude = value1string.toFloat();
k++;
}
}
fieldindex = mainString.indexOf("lat");
if(fieldindex != -1){
for (int k=9; k<20; k++){
String value1string = mainString.substring(fieldindex+5,fieldindex+k+1);
latitude = value1string.toFloat();
k++;
}
}
fieldindex = mainString.indexOf("temp");
if(fieldindex != -1){
for (int k=9; k<20; k++){
String value1string = mainString.substring(fieldindex+6,fieldindex+k+1);
temperatureK = value1string.toFloat();
k++;
}
temperatureC = (temperatureK- 273.15);
temperatureF = (temperatureC *5/9) + 32;
}
fieldindex = mainString.indexOf("pressure");
if(fieldindex != -1){
for (int k=9; k<20; k++){
String value1string = mainString.substring(fieldindex+10,fieldindex+k+1);
pressure = value1string.toFloat();
k++;
}
}
fieldindex = mainString.indexOf("humidity");
if(fieldindex != -1){
for (int k=9; k<20; k++){
String value1string = mainString.substring(fieldindex+10,fieldindex+k+1);
humidity = value1string.toFloat();
k++;
}
}
fieldindex = mainString.indexOf("visibility");
if(fieldindex != -1){
for (int k=9; k<20; k++){
String value1string = mainString.substring(fieldindex+12,fieldindex+k+1);
visibility = value1string.toFloat();
k++;
}
}
fieldindex = mainString.indexOf("speed");
if(fieldindex != -1){
for (int k=9; k<20; k++){
String value1string = mainString.substring(fieldindex+7,fieldindex+k+1);
windSpeed = value1string.toFloat();
k++;
}
}
fieldindex = mainString.indexOf("deg");
if(fieldindex != -1){
for (int k=9; k<20; k++){
String value1string = mainString.substring(fieldindex+5,fieldindex+k+1);
windDirection = value1string.toFloat();
k++;
}
}
fieldindex = mainString.indexOf("all");
if(fieldindex != -1){
for (int k=9; k<20; k++){
String value1string = mainString.substring(fieldindex+5,fieldindex+k+1);
cloud = value1string.toFloat();
k++;
}
}
fieldindex = mainString.indexOf("dt");
if(fieldindex != -1){
for (int k=9; k<20; k++){
String value1string = mainString.substring(fieldindex+4,fieldindex+k+1);
dataTime = value1string.toFloat();
k++;
}
// dataTimeString = getStringDate(dataTime);
}
fieldindex = mainString.indexOf("sunrise");
if(fieldindex != -1){
for (int k=9; k<20; k++){
String value1string = mainString.substring(fieldindex+9,fieldindex+k+1);
sunRiseTime = value1string.toFloat();
k++;
}
//sunRiseTimeString = getStringDate(sunRiseTime);
}
fieldindex = mainString.indexOf("sunset");
if(fieldindex != -1){
for (int k=9; k<20; k++){
String value1string = mainString.substring(fieldindex+8,fieldindex+k+1);
sunSetTime = value1string.toFloat();
k++;
}
//sunSetTimeString = getStringDate(sunSetTime);
}
feedindex = mainString.indexOf("weather");
if(feedindex != -1){
fieldindex = mainString.indexOf("main", feedindex);
int pos1 = mainString.indexOf(tester, fieldindex+6);
int pos2 = mainString.indexOf(tester, fieldindex+9);
weather = mainString.substring(pos1+1,pos2);
}
feedindex = mainString.indexOf("weather");
if(feedindex != -1){
fieldindex = mainString.indexOf("description", feedindex);
int pos1 = mainString.indexOf(tester, fieldindex+13);
int pos2 = mainString.indexOf(tester, fieldindex+16);
weatherDescription = mainString.substring(pos1+1,pos2);
}
feedindex = mainString.indexOf("country");
if(feedindex != -1){
int pos1 = mainString.indexOf(tester, feedindex+9);
int pos2 = mainString.indexOf(tester, feedindex+12);
countryCode = mainString.substring(pos1+1,pos2);
}
else{
countryCode = "Not Found";
}
feedindex = mainString.indexOf("name");
if(feedindex != -1){
int pos1 = mainString.indexOf(tester, feedindex+6);
int pos2 = mainString.indexOf(tester, feedindex+9);
cityName = mainString.substring(pos1+1,pos2);
}
else{
cityName = "Not Found";
}
Serial.println("latitude: " + String(latitude));
Serial.println("longitude: " + String(longitude));
Serial.println("temperatureK: " + String(temperatureK));
Serial.println("temperatureC: " + String(temperatureC));
Serial.println("humidity: " + String(humidity));
Serial.println("pressure: " + String(pressure));
Serial.println("visibility: " + String(visibility));
Serial.println("windSpeed: " + String(windSpeed));
Serial.println("windDirection: " + String(windDirection));
Serial.println("cloud: " + String(cloud));
Serial.println("rain1hr: " + String(rain1hr));
Serial.println("dataTime: " + String(dataTime));
Serial.println("sunRiseTime: " + String(sunRiseTime));
Serial.println("sunSetTime: " + String(sunSetTime));
}
float InternetModule::getLatitude()
{
return latitude;
}
float InternetModule::getLongitude()
{
return longitude;
}
float InternetModule::getPressure()
{
return pressure;
}
float InternetModule::getTemperatureC()
{
return temperatureC;
}
float InternetModule::getTemperatureF()
{
return temperatureF;
}
float InternetModule::getTemperatureK()
{
return temperatureK;
}

View File

@ -0,0 +1,64 @@
#ifndef InternetModule_h
#define InternetModule_h
#include "ModuleParent.h"
#include "CircularBuffer.h"
//Function-Id
#define HTTP_GET 0x01
#define HTTP_SUCCESS 0x02
#define HTTP_RESPONSE 0x03
class InternetModule :public ModuleParent
{
public:
//Constructor
InternetModule();
void sendGETRequest(String);
void updateChannelFeed(String KEY,int noOfData, int value1=0, int value2=0, int value3=0, int value4=0, int value5=0, int value6=0, int value7=0, int value8=0);
void updateChannelField(String KEY,uint8_t fieldNumber,int data);
float getFieldData(String KEY,uint8_t fieldNumber,long timeout=10000);
void getWeatherData(String KEY, float Lat, float Lon);
float getLatitude();
float getLongitude();
float getTemperatureK();
float getTemperatureC();
float getTemperatureF();
float getHumidity();
float getPressure();
//float getWeatherValueFloat(int feild);
//String getWeatherValueString(int feild);
private:
String mainString = "";
bool successState= 0;
void processData();
float latitude;
float longitude;
float temperatureK;
float temperatureC;
float temperatureF;
float humidity;
float pressure;
float visibility;
float windSpeed;
float windDirection;
float cloud;
float rain1hr;
float dataTime;
float sunRiseTime;
float sunSetTime;
String weather = String();
String weatherDescription = String();
String countryCode = String();
String cityName = String();
String dataTimeString = String();
String sunRiseTimeString = String();
String sunSetTimeString = String();
};
//Extern Object
extern InternetModule Internet;
#endif

View File

@ -0,0 +1,109 @@
#define FROM_DABBLE_LIBRARY
#include "DabbleESP32.h"
#include "LedControlModule.h"
#ifdef ESP32
#define MAX_PWM_CHANNELS 8
uint8_t freeChannel =0,prevPin=0,currentChannel=0;
bool pinType=0; // flag to differentiate pin behaviour means whether pin will be traeted as PWM or digital
#endif
LedControlModule::LedControlModule(): ModuleParent(LEDCONTROL_ID)
{
}
void LedControlModule::processData()
{
byte functionId =getDabbleInstance().getFunctionId();
if(functionId == 0x01)
{
pin = getDabbleInstance().getArgumentData(0)[0];
if(prevPin != pin)
{
if(freeChannel < MAX_PWM_CHANNELS)
{
#ifdef DEBUG
Serial.println("Pin is treated as pwm pin");
#endif
/*#ifdef DEBUG
Serial.print("Channels: ");
Serial.print(freeChannel);
Serial.print(" ");
Serial.println(currentChannel);
#endif*/
currentChannel = freeChannel;
ledcAttachPin(pin,currentChannel);
ledcSetup(currentChannel,100,8);
freeChannel++;
/*#ifdef DEBUG
Serial.print("freeChannels: ");
Serial.println(freeChannel);
#endif*/
pinType =1; // pin is a PWM type
}
else
{
#ifdef DEBUG
Serial.println("Pin is treated as digital pin");
#endif
pinMode(pin,OUTPUT);
pinType = 0; // pin is a digital type
}
}
prevPin = pin;
}
else if (functionId == 0x03) //ON as per Brightness value
{
brightness = getDabbleInstance().getArgumentData(0)[0];
#ifdef DEBUG
Serial.println(brightness);
#endif
value = map(brightness,0,100,0,255);
#ifdef DEBUG
Serial.println(value);
#endif
}
else if(functionId == 0x02) //OFF
{
brightness =0;
value=0;
}
if(pinType == 1 && pin!= 0) //for PWM type pin
{
//Serial.println("Value Assigned");
ledcWrite(currentChannel,value);
}
else //for digital type pin
{
//Serial.println("Value Assigned");
if(value == 255)
{
digitalWrite(pin,HIGH);
}
else
{
digitalWrite(pin,LOW);
}
}
}
uint8_t LedControlModule::readBrightness()
{
return brightness;
}
bool LedControlModule::getpinState()
{
if(brightness>0)
return 1;
else
return 0;
}
uint8_t LedControlModule::getpinNumber()
{
return pin;
}

View File

@ -0,0 +1,32 @@
#ifndef LedControlModule_h
#define LedControlModule_h
#include "ModuleParent.h"
class LedControlModule : public ModuleParent
{
public:
//Constructor
LedControlModule();
public:
uint8_t readBrightness();
bool getpinState();
uint8_t getpinNumber();
uint8_t pin;
uint8_t brightness=0;
private:
//Reserve Variables
byte value;
//bool isCallBackAssigned;
//Process Input Data
void processData();
/*void (*buttonChangeCallBack)(unsigned char , unsigned char ,
unsigned char , unsigned char ,
unsigned char ,unsigned char ,
unsigned char ,unsigned char );*/
};
//Extern Object
extern LedControlModule LedControl;
#endif

View File

@ -0,0 +1,19 @@
#define Dabble_ID 0x00
#define GAMEPAD_ID 0x01
#define TERMINAL_ID 0x02
#define CONTROLS_ID 0x05
#define EVIVEINTERFACES_ID 0x09
//#define INTERNET_ID 0x29
#define PINMONITOR_ID 0x03
#define SENSORS_ID 0x04
#define CAMERA_ID 0x06
#define LEDCONTROL_ID 0x0A
#define COLORDETECTOR_ID 0x0B
#define DATALOGGER_ID 0x0C
#define SMS_ID 0x0D
#define NOTIFICATION_ID 0x0D
#define MUSIC_ID 0x0E
#define ROBOTICARM_ID 0x0F
#define HOMEAUTOMATION_ID 0x10
#define INTERNET_ID 0x11

View File

@ -0,0 +1,14 @@
#include "motorControls.h"
#include "InternetModule.h"
#include "DabbleInputs.h"
#include "TerminalModule.h"
#include "GamePadModule.h"
#include "PinMonitorModule.h"
#include "SensorModule.h"
#include "CameraModule.h"
#include "LedControlModule.h"
#include "ColorDetectorModule.h"
#include "DataLoggerModule.h"
#include "NotifyAndSMSModule.h"
#include "MusicModule.h"

View File

@ -0,0 +1,64 @@
#ifdef INCLUDE_INTERNET_MODULE
EXTERN InternetModule Internet;
#endif
#ifdef INCLUDE_TERMINAL_MODULE
EXTERN TerminalModule Terminal;
#endif
#ifdef INCLUDE_DABBLEINPUTS_MODULE
EXTERN DabbleInputs Inputs;
#endif
#ifdef INCLUDE_MOTORCONTROL_MODULE
EXTERN motorControls Controls;
#endif
#ifdef INCLUDE_GAMEPAD_MODULE
EXTERN GamePadModule GamePad;
#endif
#ifdef INCLUDE_PINMONITOR_MODULE
EXTERN PinMonitorModule PinMonitor;
#endif
#ifdef INCLUDE_SENSOR_MODULE
EXTERN SensorModule Sensor;
#endif
#ifdef INCLUDE_CAMERA_MODULE
EXTERN CameraModule Camera;
#endif
#ifdef INCLUDE_LEDCONTROL_MODULE
EXTERN LedControlModule LedControl;
#endif
#ifdef INCLUDE_COLORDETECTOR_MODULE
EXTERN ColorDetectorModule ColorDetector;
#endif
#ifdef INCLUDE_DATALOGGER_MODULE
EXTERN DataLoggerModule DataLogger;
#endif
#ifdef INCLUDE_SMS_MODULE
EXTERN SMSModule SMS;
#endif
#ifdef INCLUDE_NOTIFICATION_MODULE
EXTERN NotificationModule Notification;
#endif
#ifdef INCLUDE_MUSIC_MODULE
EXTERN MusicModule Music;
#endif
/*#ifdef INCLUDE_ROBOTICARM_MODULE
EXTERN RoboticArmModule RoboticArm;
#endif
#ifdef INCLUDE_HOMEAUTOMATION_MODULE
EXTERN HomeAutomationModule HomeAutomation;;
#endif*/

View File

@ -0,0 +1,95 @@
#define FROM_DABBLE_LIBRARY
#include "DabbleESP32.h"
DabbleClass * ModuleParent::DabbleInstance=NULL;
bool ModuleParent::DabbleInstanceAvailable=false;
ModuleParent::ModuleParent(byte ModuleNo)
{
//Serial.println("FOUND NEW MODULE");
ModuleID = ModuleNo ;
/*#ifdef DEBUG
Serial.println(ModuleID);
#endif*/
isCallBackSet=false;
DabbleClass::addToModulesArray(this);
}
void ModuleParent::select()
{
Dabble.sendModuleFrame(ModuleID,0x00,SELECT_MODULE,0x00);
}
void ModuleParent::deselect()
{
Dabble.sendModuleFrame(ModuleID,0x00,DESELECT_MODULE,0x00);
}
void ModuleParent::setOnSelected(void (*userFunction)(void))
{
Dabble.sendModuleFrame(ModuleID,0x00,QUERY_SELECTED,0x00);
isCallBackSet=true;
selectedCallBack=userFunction;
}
byte ModuleParent::getModuleId()
{
return ModuleID;
}
void ModuleParent::enteringACallback()
{
Dabble.enteringACallback();
}
void ModuleParent::exitingACallback()
{
Dabble.exitingACallback();
}
bool ModuleParent::isInACallback()
{
return Dabble.isInACallback();
}
void ModuleParent::setDabbleInstance(DabbleClass & instance)
{
DabbleInstance=&instance;
DabbleInstanceAvailable=true;
}
void ModuleParent::unSetDabbleInstance()
{
DabbleInstance=NULL;
DabbleInstanceAvailable=false;
}
DabbleClass & ModuleParent::getDabbleInstance()
{
if(DabbleInstanceAvailable)return *DabbleInstance;
else return Dabble;
}
void ModuleParent::processFrame()
{
if(ModuleID!=getDabbleInstance().getModuleId())
{
return;
}
byte functionID = getDabbleInstance().getFunctionId();
if(functionID == CHECK_SELECTED)
{
if(isCallBackSet && !isInACallback())
{
enteringACallback();
(*selectedCallBack)();
exitingACallback();
}
}
else
{
processData();
}
}

View File

@ -0,0 +1,46 @@
#ifndef ModuleParent_h
#define ModuleParent_h
/* Output functions ID. */
#define QUERY_SELECTED 0xFF
#define SELECT_MODULE 0xFE
#define DESELECT_MODULE 0xFD
/* Input functions ID. */
#define CHECK_SELECTED 0xFF
class DabbleClass;
class ModuleParent
{
protected:
ModuleParent(byte);
virtual void processFrame(void);
virtual void processData(void){};
void enteringACallback();
void exitingACallback();
bool isInACallback();
DabbleClass & getDabbleInstance();
public:
/* Functions will be inherited by all Modules. */
void select(void);
void deselect(void);
void setOnSelected(void(*)(void));
byte getModuleId(void);
private:
bool isCallBackSet;
byte ModuleID;
void (*selectedCallBack)(void);
static DabbleClass * DabbleInstance;
static bool DabbleInstanceAvailable;
static void setDabbleInstance(DabbleClass &);
static void unSetDabbleInstance();
friend class DabbleClass;
};
#endif

View File

@ -0,0 +1,31 @@
#define ANY_MODULE_DEFINED \
(defined(INCLUDE_DABBLEINPUTS_MODULE) || \
defined(INCLUDE_GAMEPAD_MODULE) || \
defined(INCLUDE_INTERNET_MODULE) || \
defined(INCLUDE_MOTORCONTROL_MODULE) || \
defined (INCLUDE_PINMONITOR_MODULE) || \
defined(INCLUDE_TERMINAL_MODULE) || \
defined(INCLUDE_CAMERA_MODULE) || \
defined(INCLUDE_COLORDETECTOR_MODULE) || \
defined(INCLUDE_LEDCONTROL_MODULE) || \
defined(INCLUDE_DATALOGGER_MODULE) || \
defined(INCLUDE_SMS_MODULE) || \
defined(INCLUDE_NOTIFICATION_MODULE) || \
defined(INCLUDE_MUSIC_MODULE) || \
defined(INCLUDE_SENSOR_MODULE))
// defined(INCLUDE_HOMEAUTOMATION_MODULE) || \
// defined(INCLUDE_ROBOTICARM_MODULE) || \
#if !defined(FROM_DABBLE_LIBRARY)
#if (defined(INCLUDE_ALL_MODULES) && defined(CUSTOM_SETTINGS)) || (!defined(CUSTOM_SETTINGS) && !ANY_MODULE_DEFINED)
#include "IncludedModulesDefines.h"
#define ALL_MODULES_INCLUDED
#endif
#endif
#if (ANY_MODULE_DEFINED && defined(CUSTOM_SETTINGS)) || defined(ALL_MODULES_INCLUDED)
#define EXTERN
#else
#define EXTERN extern
#endif

View File

@ -0,0 +1,32 @@
#define FROM_DABBLE_LIBRARY
#include "DabbleESP32.h"
#include "MusicModule.h"
MusicModule::MusicModule():ModuleParent(MUSIC_ID)
{}
void MusicModule::play(String name){
//uint8_t namelength = strlen(name);
Dabble.sendModuleFrame(MUSIC_ID,0,PLAYNOW,1, new FunctionArg(name.length(), (byte *)&name[0]));
}
void MusicModule::addToQueue(String name){
//uint8_t namelength = strlen(name);
Dabble.sendModuleFrame(MUSIC_ID,0,ADDTOQUEUE,1, new FunctionArg(name.length(), (byte *)&name[0]));
}
void MusicModule::stop(){
Dabble.sendModuleFrame(MUSIC_ID,0,STOPMUSIC,0);
}
void MusicModule::playMusic(uint8_t a, String key)
{
if(a == 1)
{
play(key);
}
if(a == 2)
{
addToQueue(key);
}
}

View File

@ -0,0 +1,19 @@
#ifndef MusicModule_H_
#define MusicModule_H_
#include "ModuleParent.h"
#define ADDTOQUEUE 0x01
#define PLAYNOW 0x02
#define STOPMUSIC 0x03
class MusicModule:public ModuleParent
{
public:
MusicModule();
void play(String);
void addToQueue(String);
void stop();
void playMusic(uint8_t , String);
};
extern MusicModule Music;
#endif

View File

@ -0,0 +1,59 @@
#define FROM_DABBLE_LIBRARY
#include "DabbleESP32.h"
#include "NotifyAndSMSModule.h"
SMSModule::SMSModule():ModuleParent(SMS_ID)
{}
void SMSModule::sendMessage(String number, String content)
{
uint8_t* numberInt = NULL;
numberInt = new uint8_t [number.length()];
for(int i =0 ; i<number.length();i++)
{
numberInt[i] = (number.charAt(i) - 48);
/*#ifdef DEBUG
Serial.print(numberInt[i]);
#endif*/
}
/* #ifdef DEBUG
Serial.println();
#endif*/
Dabble.sendModuleFrame(SMS_ID,0,SENDNUMBER,1,new FunctionArg(number.length(), numberInt));
Dabble.sendModuleFrame(SMS_ID,0,SENDCONTENT,1,new FunctionArg(content.length(),(byte*)&content[0]));
delete [] numberInt;
}
NotificationModule::NotificationModule()
{
}
void NotificationModule::setTitle(String title)
{
Dabble.sendModuleFrame(NOTIFICATION_ID,0,CREATE_NOTIFICATION, 1, new FunctionArg(title.length(),(byte*)&title[0]));
}
void NotificationModule::notifyPhone(String content)
{
if(prevContent != content)
Dabble.sendModuleFrame(NOTIFICATION_ID,0,UPDATE_NOTIFICATION, 1, new FunctionArg(content.length(),(byte*)&content[0]));
prevContent = content;
}
void NotificationModule::clear()
{
Dabble.sendModuleFrame(NOTIFICATION_ID,0,CLEAR_NOTIFICATION,0);
prevContent = "";
}
/*void NotificationModule::notifyPhone(String title, String content)
{
if(prevTitle != title)
{
create(title);
}
message(content);
prevTitle = title;
}*/

View File

@ -0,0 +1,32 @@
#ifndef SMSModule_H_
#define SMSModule_H_
#include "ModuleParent.h"
//function -id
#define SENDNUMBER 01 // number for SMS
#define SENDCONTENT 02 // Content of Message
#define CREATE_NOTIFICATION 0x03 //for creating notification
#define UPDATE_NOTIFICATION 0x04 //for updating content
#define CLEAR_NOTIFICATION 0x05 //for clear current notification
class SMSModule:public ModuleParent
{
public:
SMSModule();
void sendMessage(String Number, String Content);
};
class NotificationModule
{
public:
NotificationModule();
void setTitle(String);
void notifyPhone(String content);
void clear();
private:
String prevContent="";
};
extern SMSModule SMS;
extern NotificationModule Notification;
#endif

View File

@ -0,0 +1,79 @@
#define FROM_DABBLE_LIBRARY
#include "DabbleESP32.h"
#include "PinMonitorModule.h"
PinMonitorModule::PinMonitorModule() : ModuleParent(PINMONITOR_ID)
{
}
/*void PinMonitorModule::write(char data)
{
Dabble.sendModuleFrame(PINMONITOR_ID,0,function_id_d,1,new FunctionArg(1,(byte *)&data));
}*/
void PinMonitorModule::processData()
{
//Serial.println(getDabbleInstance().getFunctionId());
}
void PinMonitorModule::sendDigitalData()
{
digitaldata = new byte[n];
for(int i=0;i<n;i++)
{
digitaldata[i]=0;
}
for(int j=0;j<n;j++)
{
for(int i=0;i<8;i++)
{
digitaldata[j] = digitaldata[j] + ((digitalRead(digital_pins[j][i]))<<i);
}
}
/*#ifdef DEBUG //Remove from final file
for(int j=0;j<n;j++)
{
Serial.print(digitaldata[j],BIN);
Serial.print(" ");
}
Serial.println();
#endif*/
if(getDabbleInstance().getScreenId()==1 && getDabbleInstance().readModuleId()==3)
{
Dabble.sendModuleFrame(PINMONITOR_ID,0,function_id_d,1,new FunctionArg(n,digitaldata));
}
delete [] digitaldata;
}
void PinMonitorModule::sendAnalogData()
{
uint8_t counter=0;
analog_data = new byte[m];
for(int i=0;i<m;i++)
{
analog_data[i]=0;
}
for (int i = 0; i < m; i=i+2)
{
analog_data[i] = (analog_pin[counter]-30) << 4;
analog_data[i] = analog_data[i] | ((analogRead(analog_pin[counter]) & 0x0F00) / 256);
analog_data[i+1]= (analogRead(analog_pin[counter]) & 0x00ff);
counter++;
}
/*#ifdef DEBUG //Remove from final file
for(int j=0;j<m;j++)
{
Serial.print(analog_data[j],BIN);
Serial.print(" ");
}
Serial.println();
#endif*/
//Dabble.sendModuleFrame(PINMONITOR_ID,0,function_id_a,1,new FunctionArg(m,analog_data));
if(getDabbleInstance().getScreenId()==3 && getDabbleInstance().readModuleId()==3)
{
Dabble.sendModuleFrame(PINMONITOR_ID,0,function_id_a,1,new FunctionArg(m,analog_data));
}
delete [] analog_data;
}

View File

@ -0,0 +1,37 @@
#ifndef PinMonitorModule_h
#define PinMonitorModule_h
#include "ModuleParent.h"
#include "Arduino.h"
//#include "SoftwareSerial.h"
class PinMonitorModule : public ModuleParent
{
byte* digitaldata=NULL;
byte* analog_data=NULL;
public:
#if defined(ESP32)
//byte byte_pins[2];
byte function_id_d = 0x06;
byte function_id_a= 0x05;
uint8_t n=4;
uint8_t m=12;
uint8_t digital_pins[4][8]={{2,0,4,5,0,0,0,0},{0,0,12,13,14,15,16,17},{18,19,0,21,22,23,0,25},{26,27,0,0,0,0,0,0}};
uint8_t analog_pin[6]={32,33,34,35,36,39};
//uint8_t analog_data[12];
#endif
public:
PinMonitorModule();
void sendDigitalData();
void sendAnalogData();
private:
void processData();
};
extern PinMonitorModule PinMonitor;
#endif

View File

@ -0,0 +1,304 @@
#define FROM_DABBLE_LIBRARY
#include "DabbleESP32.h"
#include "SensorModule.h"
SensorModule::SensorModule(): ModuleParent(SENSORS_ID)
{
}
float SensorModule::getAccelerometerXaxis()
{
return accelo_x;
}
float SensorModule::getAccelerometerYaxis()
{
return accelo_y;
}
float SensorModule::getAccelerometerZaxis()
{
return accelo_z;
}
float SensorModule::getGyroscopeXaxis()
{
return gyro_x;
}
float SensorModule::getGyroscopeYaxis()
{
return gyro_y;
}
float SensorModule::getGyroscopeZaxis()
{
return gyro_z;
}
float SensorModule::getMagnetometerXaxis()
{
return magneto_x;
}
float SensorModule::getMagnetometerYaxis()
{
return magneto_y;
}
float SensorModule::getMagnetometerZaxis()
{
return magneto_z;
}
float SensorModule::getProximityDistance()
{
return proximity;
}
float SensorModule::getLightIntensity()
{
return light;
}
float SensorModule::getSoundDecibels()
{
return sound_level;
}
float SensorModule::getTemperature()
{
return temperature;
}
float SensorModule::getBarometerPressure()
{
return barometer;
}
float SensorModule::getGPSlongitude()
{
return gps_longitude;
}
float SensorModule::getGPSLatitude()
{
return gps_latitude;
}
float SensorModule::getdata_Accelerometer_xaxis()
{
return accelo_x;
}
float SensorModule::getdata_Accelerometer_yaxis()
{
return accelo_y;
}
float SensorModule::getdata_Accelerometer_zaxis()
{
return accelo_z;
}
float SensorModule::getdata_Gyroscope_xaxis()
{
return gyro_x;
}
float SensorModule::getdata_Gyroscope_yaxis()
{
return gyro_y;
}
float SensorModule::getdata_Gyroscope_zaxis()
{
return gyro_z;
}
float SensorModule::getdata_Magnetometer_xaxis()
{
return magneto_x;
}
float SensorModule::getdata_Magnetometer_yaxis()
{
return magneto_y;
}
float SensorModule::getdata_Magnetometer_zaxis()
{
return magneto_z;
}
float SensorModule::getdata_Proximity()
{
return proximity;
}
float SensorModule::getdata_Light()
{
return light;
}
float SensorModule::getdata_Sound()
{
return sound_level;
}
float SensorModule::getdata_Temperature()
{
return temperature;
}
float SensorModule::getdata_Barometer()
{
return barometer;
}
float SensorModule::getdata_GPS_longitude()
{
return gps_longitude;
}
float SensorModule::getdata_GPS_latitude()
{
return gps_latitude;
}
float SensorModule::getSensorData(uint8_t a)
{
if(a==0)
{
return accelo_x;
}
else if(a==1)
{
return accelo_y;
}
else if(a==2)
{
return accelo_z;
}
else if(a==3)
{
return gyro_x;
}
else if(a==4)
{
return gyro_y;
}
else if(a==5)
{
return gyro_z;
}
else if(a==6)
{
return magneto_x;
}
else if(a==7)
{
return magneto_y;
}
else if(a==8)
{
return magneto_z;
}
else if(a==9)
{
return proximity;
}
else if(a==10)
{
return temperature;
}
else if(a==11)
{
return sound_level;
}
else if(a==12)
{
return barometer;
}
else if(a==13)
{
return gps_longitude;
}
else if(a==14)
{
return gps_latitude;
}
else if(a==15)
{
return light;
}
}
void SensorModule::processData()
{
byte functionId =getDabbleInstance().getFunctionId();
if(functionId == ACCELEROMETER || functionId == GYROSCOPE || functionId == MAGNETOMETER)
{
if(functionId == ACCELEROMETER)
{
accelo_x = getDabbleInstance().convertBytesToFloat(getDabbleInstance().getArgumentData(0));
accelo_y = getDabbleInstance().convertBytesToFloat(getDabbleInstance().getArgumentData(1));
accelo_z = getDabbleInstance().convertBytesToFloat(getDabbleInstance().getArgumentData(2));
}
else if(functionId == GYROSCOPE)
{
gyro_x = getDabbleInstance().convertBytesToFloat(getDabbleInstance().getArgumentData(0));
gyro_y = getDabbleInstance().convertBytesToFloat(getDabbleInstance().getArgumentData(1));
gyro_z = getDabbleInstance().convertBytesToFloat(getDabbleInstance().getArgumentData(2));
}
else if(functionId == MAGNETOMETER)
{
magneto_x = getDabbleInstance().convertBytesToFloat(getDabbleInstance().getArgumentData(0));
magneto_y = getDabbleInstance().convertBytesToFloat(getDabbleInstance().getArgumentData(1));
magneto_z = getDabbleInstance().convertBytesToFloat(getDabbleInstance().getArgumentData(2));
}
}
if(functionId == PROXIMITY || functionId == TEMPERATURE || functionId == LIGHT || functionId == SOUND || functionId == BAROMETER)
{
if(functionId == PROXIMITY )
{
proximity = getDabbleInstance().convertBytesToFloat(getDabbleInstance().getArgumentData(0));
}
else if(functionId == TEMPERATURE)
{
temperature = getDabbleInstance().convertBytesToFloat(getDabbleInstance().getArgumentData(0));
}
else if(functionId == SOUND)
{
sound_level = getDabbleInstance().convertBytesToFloat(getDabbleInstance().getArgumentData(0));
}
else if(functionId == BAROMETER)
{
barometer = getDabbleInstance().convertBytesToFloat(getDabbleInstance().getArgumentData(0));
}
else if(functionId == LIGHT)
{
light = getDabbleInstance().convertBytesToFloat(getDabbleInstance().getArgumentData(0));
}
}
if(functionId == GPS)
{
gps_longitude = getDabbleInstance().convertBytesToFloat(getDabbleInstance().getArgumentData(1));
gps_latitude = getDabbleInstance().convertBytesToFloat(getDabbleInstance().getArgumentData(0));
}
}

View File

@ -0,0 +1,86 @@
#ifndef SensorModule_h
#define SensorModule_h
#include "ModuleParent.h"
#include <math.h>
#define ACCELEROMETER 0x01
#define GYROSCOPE 0x02
#define MAGNETOMETER 0x03
#define PROXIMITY 0x04
#define LIGHT 0x05
#define SOUND 0x06
#define TEMPERATURE 0x07
#define BAROMETER 0x08
#define GPS 0x09
class SensorModule: public ModuleParent
{
public:
SensorModule();
float getdata_Accelerometer_xaxis();
float getdata_Accelerometer_yaxis();
float getdata_Accelerometer_zaxis();
float getdata_Gyroscope_xaxis();
float getdata_Gyroscope_yaxis();
float getdata_Gyroscope_zaxis();
float getdata_Magnetometer_xaxis();
float getdata_Magnetometer_yaxis();
float getdata_Magnetometer_zaxis();
float getdata_Proximity();
float getdata_Light();
float getdata_Sound();
float getdata_Temperature();
float getdata_Barometer();
float getdata_GPS_longitude();
float getdata_GPS_latitude();
float getAccelerometerXaxis();
float getAccelerometerYaxis();
float getAccelerometerZaxis();
float getGyroscopeXaxis();
float getGyroscopeYaxis();
float getGyroscopeZaxis();
float getMagnetometerXaxis();
float getMagnetometerYaxis();
float getMagnetometerZaxis();
float getProximityDistance();
float getLightIntensity();
float getSoundDecibels();
float getTemperature();
float getBarometerPressure();
float getGPSlongitude();
float getGPSLatitude();
float getSensorData(uint8_t a);
void processData();
public:
byte sensorvalue_x[4];
byte sensorvalue_y[4];
byte sensorvalue_z[4];
byte sensor_data[4];
byte sensor_data_1[4];
float accelo_x=0;
float accelo_y=0;
float accelo_z=0;
float gyro_x=0;
float gyro_y=0;
float gyro_z=0;
float magneto_x=0;
float magneto_y=0;
float magneto_z=0;
float proximity=0;
float light=0;
float barometer=0;
float gps_longitude=0;
float gps_latitude=0;
float sound_level=0;
float temperature=0;
};
extern SensorModule Sensor;
#endif

View File

@ -0,0 +1,171 @@
#define FROM_DABBLE_LIBRARY
#include "DabbleESP32.h"
#include "TerminalModule.h"
//String comparestring= "";
String numberString= "";
String stringData= "";
String comparestring="";
bool stringclearflag1=0;
bool stringclearflag2=0;
bool stringclearflag3=0;
//Constructor
TerminalModule::TerminalModule():PrintlnClass(TERMINAL_ID,TERMINAL_WRITE,TERMINAL_PRINT),ModuleParent(TERMINAL_ID)
{}
//Read from Android
char TerminalModule::read()
{
if(buffer.remain()<=0)return -1;
return buffer.pop();
}
//Flush buffer contents
void TerminalModule::flush()
{
while(read()!=-1);
}
//Check Data avialable in Buffer
int TerminalModule::available()
{
return buffer.remain();
}
//Read bytes from Buffer
int TerminalModule::readBytes(char *arr, int length)
{
int count = 0;
while (count < length) {
int c = read();
if (c < 0) break;
*arr++ = (char)c;
count++;
}
return count;
}
//Terminal Incomming Data processing
void TerminalModule::processData()
{
byte functionID = getDabbleInstance().getFunctionId();
byte dataLength = getDabbleInstance().getArgumentLength(0);
if(functionID == TERMINAL_READ)
{
for (int j=0; j<dataLength; j++)
{
buffer.push(getDabbleInstance().getArgumentData(0)[j]);
//buffer1.push(getDabbleInstance().getArgumentData(0)[j]);
}
}
}
bool TerminalModule::compareString(String text)
{
String compareData= "";
readString();
compareData = comparestring;
//Serial.println("Terminal String" + comparestring);
if(stringclearflag3 ==1)
{
compareData= "";
}
if(compareData == text)
{
stringclearflag3 =1;
return 1;
}
else
{
return 0;
}
}
/*int TerminalModule::readNumber()
{
int numberData;
bool a =0;
String numCheck=stringData;
for(int i=0;i<numCheck.length();i++)
{
if(numCheck.charAt(i)>47 && numCheck.charAt(i)<58)
{
a=1;
}
}
if(a==1)
{
numberData= numCheck.toInt();
}
else
{
numberData=-30000;
}
return numberData;
}*/
String TerminalModule::readString()
{
if(buffer.remain()>0)
{
stringclearflag1=0;
stringclearflag2=0;
stringclearflag3=0;
//comparestring="";
//numberstring="";
stringData= "";
while(buffer.remain()>0)
{
char a = buffer.pop();
stringData=String(stringData+a);
numberString=stringData;
comparestring=stringData;
//comparestring=String(comparestring+a);
//numberstring=String(numberstring+a);
}
}
if(stringclearflag1==0)
{
stringclearflag1 =1;
return stringData;
}
else
{
stringData = "";
return stringData;
}
}
int TerminalModule::readNumber()
{
int numberData;
bool a=0;
readString();
for(int i=0;i<numberString.length();i++)
{
if(numberString.charAt(i)>47 && numberString.charAt(i)<58)
{
a=1;
}
else
{
break;
}
}
if(a==1 && stringclearflag2 == 0)
{
stringclearflag2=1;
numberData= numberString.toInt();
}
else
{
numberData=-100;
}
return numberData;
}

View File

@ -0,0 +1,44 @@
#ifndef TerminalModule_h
#define TerminalModule_h
#include "ModuleParent.h"
#include "DabblePrintln.h"
#include "CircularBuffer.h"
//Output Function ID's
#define TERMINAL_WRITE 0x02
#define TERMINAL_PRINT 0x02
//Input Function ID
#define TERMINAL_READ 0x01
class TerminalModule : public PrintlnClass, public ModuleParent
{
public:
//Constructor
TerminalModule();
//Checker
int available();
//Getter
char read();
//Getter
int readBytes(char *, int);
//Setter
void flush();
String readString();
bool compareString(String text);
int readNumber();
private:
//Instatiate Object from class CircularBuffer
CircularBuffer<char,64> buffer;
//CircularBuffer<char,64> buffer1;
//Process Input data
void processData();
};
//Extern Object
extern TerminalModule Terminal;
#endif

View File

@ -0,0 +1,189 @@
#if defined(ESP32)
#include "esp32BLEUtilities.h"
bool BLE_status=0;
bool isDeviceConnected=false;
bool prevDeviceConnected = false;
uint8_t tx_Value = 0;
uint8_t rxdatalength=0;
uint8_t bytesremaining=0;
uint8_t* rxdataBuffer=NULL;
bool newDataReceived = 0;
BLEServer *bleServer = NULL;
BLECharacteristic *bleTxCharacteristic;
class BleServerCallbacks: public BLEServerCallbacks {
void onConnect(BLEServer* bleServer) {
isDeviceConnected = true;
};
void onDisconnect(BLEServer* bleServer) {
isDeviceConnected = false;
}
};
class BleCallbacks: public BLECharacteristicCallbacks {
void onWrite(BLECharacteristic *bleCharacteristic) {
std::string rx_Value = bleCharacteristic->getValue();
if(newDataReceived == 1)delete [] rxdataBuffer;
newDataReceived = 1;
if (rx_Value.length() > 0) {
rxdataBuffer = new uint8_t[rx_Value.length()];
for (int i = 0; i < rx_Value.length(); i++)
{
rxdataBuffer[i] = rx_Value[i];
#ifdef DEBUG
Serial.print(rxdataBuffer[i]);
Serial.print(" ");
#endif
}
#ifdef DEBUG
Serial.println();
#endif
rxdatalength=rx_Value.length();
bytesremaining=rx_Value.length();
}
}
};
void Esp32ble::begin(std::string a)
{
BLEDevice::init(a);
// Create the BLE Server
bleServer = BLEDevice::createServer();
bleServer->setCallbacks(new BleServerCallbacks());
// Create the BLE Service
BLEService *bleService = bleServer->createService(UUID_Service);
// Create a BLE Characteristic
bleTxCharacteristic = bleService->createCharacteristic(
UUID_Transmit,
BLECharacteristic::PROPERTY_NOTIFY
);
bleTxCharacteristic->addDescriptor(new BLE2902());
BLECharacteristic * bleRxCharacteristic = bleService->createCharacteristic(
UUID_Receive,
BLECharacteristic::PROPERTY_WRITE
);
bleRxCharacteristic->setCallbacks(new BleCallbacks());
// Start the service
bleService->start();
// Start advertising
bleServer->getAdvertising()->start();
#ifdef DEBUG
Serial.println("Waiting a client connection to notify...");
#endif
}
void Esp32ble::write(uint8_t a)
{
if (isDeviceConnected) {
bleTxCharacteristic->setValue(&a,1);
bleTxCharacteristic->notify();
delay(10); // bluetooth stack will go into congestion, if too many packets are sent
}
// disconnecting
if (!isDeviceConnected && prevDeviceConnected) {
delay(500); // give the bluetooth stack the chance to get things ready
bleServer->startAdvertising(); // restart advertising
#ifdef DEBUG
Serial.println("start advertising");
#endif
prevDeviceConnected = isDeviceConnected;
}
}
void Esp32ble::write(std::string x)
{
if (isDeviceConnected) {
bleTxCharacteristic->setValue(x);
bleTxCharacteristic->notify();
delay(10); // bluetooth stack will go into congestion, if too many packets are sent
}
// disconnecting
if (!isDeviceConnected && prevDeviceConnected) {
delay(500); // give the bluetooth stack the chance to get things ready
bleServer->startAdvertising(); // restart advertising
#ifdef DEBUG
Serial.println("start advertising");
#endif
prevDeviceConnected = isDeviceConnected;
}
}
void Esp32ble::write(int a)
{
if (isDeviceConnected) {
bleTxCharacteristic->setValue(a);
bleTxCharacteristic->notify();
delay(10); // bluetooth stack will go into congestion, if too many packets are sent
}
// disconnecting
if (!isDeviceConnected && prevDeviceConnected) {
delay(500); // give the bluetooth stack the chance to get things ready
bleServer->startAdvertising(); // restart advertising
#ifdef DEBUG
Serial.println("start advertising");
#endif
prevDeviceConnected = isDeviceConnected;
}
}
void Esp32ble::write(float a)
{
if (isDeviceConnected) {
bleTxCharacteristic->setValue(a);
bleTxCharacteristic->notify();
delay(10); // bluetooth stack will go into congestion, if too many packets are sent
}
// disconnecting
if (!isDeviceConnected && prevDeviceConnected) {
delay(500); // give the bluetooth stack the chance to get things ready
bleServer->startAdvertising(); // restart advertising
#ifdef DEBUG
Serial.println("start advertising");
#endif
prevDeviceConnected = isDeviceConnected;
}
}
uint8_t Esp32ble::available()
{
return bytesremaining;
}
uint8_t Esp32ble::read()
{
if(bytesremaining > 0)
{
uint8_t a = rxdataBuffer[rxdatalength-bytesremaining];
bytesremaining--;
return a;
}
else
{
return 0;
}
}
void Esp32ble::stop()
{
btStop();
}
Esp32ble esp32ble;
#endif

View File

@ -0,0 +1,31 @@
#if (defined(ESP32))
#ifndef BLE_UTILITIES_H
#define BLE_UTILITIES_H
#include <Arduino.h>
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>
#define UUID_Service "6E400001-B5A3-F393-E0A9-E50E24DCCA9E"
#define UUID_Transmit "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"
#define UUID_Receive "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"
class Esp32ble
{
public:
void begin(std::string a);
void write(uint8_t a);
void write(std::string x);
void write(int a);
void write(float a);
uint8_t available();
uint8_t read();
void stop();
};
extern bool BLE_status; //extern BLE_status
extern Esp32ble esp32ble;
#endif
#endif

View File

@ -0,0 +1,207 @@
#include "esp32PWMUtilities.h"
static bool freeChannelFlag[7] = {0,0,0,0,0,0,0};
static uint8_t currentFreeChannel = 6;
static int channelPinMap[7] = {-1,-1,-1,-1,-1,-1,-1};
int frequency=50;
uint8_t totalFreeChannel = 0;
static bool flag = false;
//PWM control
void analogWrite(uint8_t pin , uint8_t value)
{
uint8_t channel;
bool isNewPin = true;
for(int8_t i = 0 ; i< 7; i++)
{
if(channelPinMap[i] == pin)
{
channel = i;
isNewPin = false;
//////Serial.println("case1");
break;
}
if(i == (6) && isNewPin == true)
{
Serial.println("case2");
if(currentFreeChannel >= totalFreeChannel)
{
Serial.println("case3");
ledcAttachPin(pin , currentFreeChannel);
channelPinMap[currentFreeChannel] = pin;
ledcSetup(currentFreeChannel,frequency,8);
channel = currentFreeChannel;
currentFreeChannel--;
}
}
}
//Serial.print("channel: ");
//Serial.println(channel);
ledcWrite(channel,value);
}
//TMotor
TMotor::TMotor(){
}
void TMotor::attach(uint8_t motorpin, uint8_t dir1, uint8_t dir2)
{
/************For Exanpder****************/
//expander.pinMode(dir1,OUTPUT);
//exapnder.pinMode(dir2,OUTPUT);
/*******************************/
pinMode(dir1,OUTPUT);
pinMode(dir2,OUTPUT);
if(flag == false) ///////////////////////////
{
flag = true;
//Serial.println("Initialized");
//expander.begin();
} ///////////////////////////
//////Serial.println("pin: " + String(motorpin));
bool isNewPin = true;
pwmPin = motorpin;
direction1 = dir1;
direction2 = dir2;
for(int8_t i = 0 ; i < 7; i++)
{
if(channelPinMap[i] == motorpin)
{
motorChannel = i;
isNewPin = false;
Serial.println("case4");
break;
}
if(i == (6) && isNewPin == true)
{
Serial.println("case5");
if(currentFreeChannel >= totalFreeChannel)
{
Serial.println("case6");
ledcAttachPin(motorpin , currentFreeChannel);
Serial.println("channel: " + String(currentFreeChannel) +" " + String(motorpin));
channelPinMap[currentFreeChannel] = motorpin;
Serial.println(channelPinMap[currentFreeChannel]);
ledcSetup(currentFreeChannel,frequency,8);
motorChannel = currentFreeChannel;
currentFreeChannel--;
}
}
Serial.println("channelPinMap: " + String(channelPinMap[i]));
}
Serial.println("motorChannel: " + String(motorChannel));
}
void TMotor::moveMotor(int pwm)
{
Serial.println("motorChannelf: " + String(motorChannel));
if(pwm >= 0)
{
//expander.digitalWrite(direction1,HIGH);
//expander.digitalWrite(direction2,LOW);
digitalWrite(direction1,HIGH);
digitalWrite(direction2,LOW);
ledcWrite(motorChannel,pwm);
}
if(pwm < 0)
{
//expander.digitalWrite(direction1,LOW);
//expander.digitalWrite(direction2,HIGH);
digitalWrite(direction1,LOW);
digitalWrite(direction2,HIGH);
ledcWrite(motorChannel,pwm);
}
}
void TMotor::lockMotor()
{
// expander.digitalWrite(direction1,HIGH);
// expander.digitalWrite(direction2,HIGH);
digitalWrite(direction1,HIGH);
digitalWrite(direction2,HIGH);
ledcWrite(motorChannel,0);
}
void TMotor::freeMotor()
{
digitalWrite(direction1,LOW);
digitalWrite(direction2,LOW);
ledcWrite(motorChannel,0);
}
void TMotor::moveMotorS(uint8_t dir,uint8_t pwm)
{
if(dir == 1)
{
digitalWrite(direction1,HIGH);
digitalWrite(direction2,LOW);
ledcWrite(motorChannel,pwm);
}
if(dir == 2)
{
digitalWrite(direction1,LOW);
digitalWrite(direction2,HIGH);
ledcWrite(motorChannel,pwm);
}
}
//Servo
void Servo::attach(uint8_t pin)
{
bool isNewPin = true;
for(int8_t i = 0 ; i<7; i++)
{
if(channelPinMap[i] == pin)
{
servoChannel = i;
isNewPin = false;
break;
}
if(i == (6) && isNewPin == true)
{
if(currentFreeChannel >= totalFreeChannel)
{
ledcAttachPin(pin , currentFreeChannel);
channelPinMap[currentFreeChannel] = pin;
ledcSetup(currentFreeChannel,50,16);
servoChannel = currentFreeChannel;
currentFreeChannel--;
}
}
Serial.println("channelPinMap: " + String(channelPinMap[i]));
}
Serial.println("servoChannel: " + String(servoChannel));
}
uint16_t Servo::degreeToMicroseconds(int degree)
{
degree = constrain(degree,minimumAngle,maximumAngle);
return map(degree,minimumAngle,maximumAngle,minimumPulseWidth,maximumPulseWidth);
}
uint16_t Servo::microsecondsToPulsewidth(int pulse)
{
pulse=constrain(pulse,minimumPulseWidth,maximumPulseWidth);
return map(pulse,0,20000,0,65535);
}
void Servo::write(uint8_t angle)
{
Serial.println("servoChannelf: " + String(servoChannel));
uint16_t pulse = degreeToMicroseconds(angle);
Serial.print(pulse);
Serial.print(" ");
uint16_t duty = microsecondsToPulsewidth(pulse);
Serial.println(duty);
ledcWrite(servoChannel,duty);
}

View File

@ -0,0 +1,35 @@
#ifndef esp32PWMUtilities
#define esp32PWMUtilities
#include "Arduino.h"
void analogWrite(uint8_t pin, uint8_t pwm);
class TMotor{
public:
TMotor();
void attach(uint8_t , uint8_t ,uint8_t);
void moveMotor(int pwm);
void lockMotor();
void freeMotor();
void moveMotorS(uint8_t dir,uint8_t pwm);
private:
uint8_t motorChannel;
uint8_t pwmPin;
uint8_t direction1;
uint8_t direction2;
};
class Servo{
public:
void write(uint8_t);
void attach(uint8_t);
private:
uint16_t minimumPulseWidth=544;
uint16_t maximumPulseWidth=2400;
uint8_t minimumAngle=0;
uint8_t maximumAngle=180;
uint8_t servoChannel;
uint16_t degreeToMicroseconds(int);
uint16_t microsecondsToPulsewidth(int);
};
#endif

View File

@ -0,0 +1,209 @@
#define FROM_DABBLE_LIBRARY
#include "DabbleESP32.h"
#include "motorControls.h"
int motorControls::minPulseWidth = 544;
int motorControls::maxPulseWidth = 2400;
int motorControls::minAngle = 0;
int motorControls::maxAngle = 180;
motorControls::motorControls() : ModuleParent(CONTROLS_ID)
{
}
void motorControls::processData()
{
/* #ifdef DEBUG
Serial.println("Controls:processData");
#endif */
functionId=getDabbleInstance().getFunctionId();
if(functionId == 0x01 || functionId == 0x02)
{
byte1=getDabbleInstance().getArgumentData(0)[0];
byte2=getDabbleInstance().getArgumentData(0)[1];
#ifdef DEBUG
Serial.print("byte1: ");
Serial.print(byte1);
Serial.print("byte2: ");
Serial.println(byte2);
#endif
if(functionId == 0x01)
{
if(byte1 == 0xf0)
{
pwmMotor1=byte2;
}
else if(byte1 == 0xff)
{
pwmMotor1= -byte2;
}
else if(byte1 == 0x0f)
{
pwmMotor1= 0;
}
else if(byte1 == 0x00)
{
pwmMotor1= 0;
}
}
if(functionId == 0x02)
{
if(byte1 == 0xf0)
{
pwmMotor2= byte2;
}
else if(byte1 == 0xff)
{
pwmMotor2= -byte2;
}
else if(byte1 == 0x0f)
{
pwmMotor2= 0;
}
else if(byte1 == 0x00)
{
pwmMotor2= 0;
}
}
}
else if(functionId == 0x03 || functionId == 0x04)
{
byte1=getDabbleInstance().getArgumentData(0)[0];
#ifdef DEBUG
Serial.print("byte1:");
Serial.println(byte1);
#endif
if(functionId == 0x03)
{
angleServo1=byte1;
}
else if(functionId == 0x04)
{
angleServo2=byte1;
}
}
}
void motorControls::runMotor1(uint8_t pwm,uint8_t direction1,uint8_t direction2)
{
pinMode(direction1,OUTPUT);
pinMode(direction2,OUTPUT);
if(prevMotor1pin != pwm)
{
ledcAttachPin(pwm,0);
ledcSetup(0,100,8);
}
if(pwmMotor1 > 0)
{
digitalWrite(direction1,HIGH);
digitalWrite(direction2,LOW);
ledcWrite(0,pwmMotor1);
}
else if(pwmMotor1 < 0)
{
digitalWrite(direction1,LOW);
digitalWrite(direction2,HIGH);
ledcWrite(0,-pwmMotor1); //making negative pwm value positive
}
else
{
digitalWrite(direction1,LOW);
digitalWrite(direction2,LOW);
ledcWrite(0,0);
}
prevMotor1pin = pwm;
}
void motorControls::runMotor2(uint8_t pwm,uint8_t direction1,uint8_t direction2)
{
pinMode(direction1,OUTPUT);
pinMode(direction2,OUTPUT);
if(prevMotor2pin != pwm)
{
ledcAttachPin(pwm,1);
ledcSetup(1,100,8);
}
if(pwmMotor2 > 0)
{
/*#ifdef DEBUG
Serial.print(direction1);
Serial.print(" ");
Serial.println(direction2);
Serial.println("Clockwise");
#endif*/
digitalWrite(direction1,HIGH);
digitalWrite(direction2,LOW);
ledcWrite(1,pwmMotor2);
}
else if(pwmMotor2 < 0)
{
/*#ifdef DEBUG
Serial.print(direction1);
Serial.print(" ");
Serial.println(direction2);
Serial.println("Anti-Clockwise");*
#endif*/
digitalWrite(direction1,LOW);
digitalWrite(direction2,HIGH);
ledcWrite(1,-pwmMotor2); //making negative pwm value positive
}
else
{
digitalWrite(direction1,LOW);
digitalWrite(direction2,LOW);
ledcWrite(1,0);
}
prevMotor2pin = pwm;
}
void motorControls::runServo1(uint8_t pin) //Attach Servo1 to channel 3
{
if(prevServo1pin!=pin)
{
ledcAttachPin(pin,3);
ledcSetup(3,50,16);
}
writeServoAngle(angleServo1,3);
prevServo1pin = pin;
}
void motorControls::runServo2(uint8_t pin) //Attach Servo2 to channel 4
{
if(prevServo2pin!=pin)
{
ledcAttachPin(pin,4);
ledcSetup(4,50,16);
}
writeServoAngle(angleServo2,4);
prevServo2pin = pin;
}
int motorControls::angleTomicroseconds(int degree)
{
degree = constrain(degree,minAngle,maxAngle);
return map(degree,minAngle,maxAngle,minPulseWidth,maxPulseWidth);
}
int motorControls::microsecondsToDuty(int pulse)
{
pulse=constrain(pulse,minPulseWidth,maxPulseWidth);
return map(pulse,0,20000,0,65535);
}
void motorControls::writeServoAngle(int angle,uint8_t channel)
{
/*Serial.print(angle);
Serial.print(" ");
Serial.println(channel);*/
int _pulse = angleTomicroseconds(angle);
int _duty = microsecondsToDuty(_pulse);
ledcWrite(channel,_duty);
}

View File

@ -0,0 +1,54 @@
#ifndef motorControls_h
#define motorControls_h
#include "ModuleParent.h"
class motorControls : public ModuleParent
{
public:
motorControls();
//Pictobox and Arduino
void runMotor1(uint8_t pwm,uint8_t direction1,uint8_t direction2);
void runMotor2(uint8_t pwm,uint8_t direction1,uint8_t direction2);
void runServo1(uint8_t pin);
void runServo2(uint8_t pin);
public:
byte byte1;
byte byte2;
uint8_t angleServo1=0;
uint8_t angleServo2=0;
int pwmMotor1=0;
int pwmMotor2=0;
byte functionId;
private:
void processData();
uint8_t prevMotor1pin = 0;
uint8_t prevMotor2pin = 0;
uint8_t prevServo1pin = 0;
uint8_t prevServo2pin = 0;
static int minPulseWidth;
static int maxPulseWidth;
static int minAngle;
static int maxAngle;
int angleTomicroseconds(int degree);
int microsecondsToDuty(int pulse);
void writeServoAngle(int angle,uint8_t channel);
};
//void runMotor1(int a);
//void runMotor2(int b);
extern motorControls Controls;
#endif

View File

@ -1,5 +0,0 @@
{
"files.associations": {
"tft_espi_esp32_s3.c": "cpp"
}
}

21
lib/TouchLib/LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2022 Micky
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

2
lib/TouchLib/README.md Normal file
View File

@ -0,0 +1,2 @@
# TouchLib
In order to integrate the touch driver, let the touch interface be unified. (The following chips are currently supported. CST328, CST816, CST820, GT911)

View File

@ -0,0 +1,92 @@
#define TOUCH_MODULES_GT911
//#define TOUCH_MODULES_CST_SELF
//#define TOUCH_MODULES_CST_MUTUAL
//#define TOUCH_MODULES_ZTW622
//#define TOUCH_MODULES_L58
#include "Arduino.h"
#include "TouchLib.h"
#include "Wire.h"
#define PIN_IIC_SCL 48
#define PIN_IIC_SDA 8
#define PIN_TOUCH_INT 1
#define PIN_TOUCH_RES 2
#define TOUCH_READ_FROM_INTERRNUPT 0
TouchLib touch(Wire, PIN_IIC_SDA, PIN_IIC_SCL, GT911_SLAVE_ADDRESS2);
void scan_i2c_device(TwoWire &i2c)
{
Serial.println("Scanning for I2C devices ...");
Serial.print(" ");
for (int i = 0; i < 0x10; i++)
{
Serial.printf("0x%02X|", i);
}
uint8_t error;
for (int j = 0; j < 0x80; j += 0x10)
{
Serial.println();
Serial.printf("0x%02X |", j);
for (int i = 0; i < 0x10; i++)
{
Wire.beginTransmission(i | j);
error = Wire.endTransmission();
if (error == 0)
Serial.printf("0x%02X|", i | j);
else
Serial.print(" -- |");
}
}
Serial.println();
}
bool get_int = false;
void setup()
{
Serial.begin(115200);
Serial.println("Hello T-Display-S3");
pinMode(PIN_TOUCH_RES, OUTPUT);
digitalWrite(PIN_TOUCH_RES, 0);
delay(200);
digitalWrite(PIN_TOUCH_RES, 1);
delay(200);
Wire.begin(PIN_IIC_SDA, PIN_IIC_SCL);
scan_i2c_device(Wire);
touch.init();
#if (TOUCH_READ_FROM_INTERRNUPT)
attachInterrupt(
PIN_TOUCH_INT,
[]
{
get_int = 1;
Serial.println("get_int");
},
CHANGE);
#endif
}
void loop()
{
delay(5);
#if (TOUCH_READ_FROM_INTERRNUPT)
if (get_int)
{
get_int = 0;
touch.read();
#else
if (touch.read())
{
#endif
uint8_t n = touch.getPointNum();
Serial.printf("getPointNum: %d ", n);
for (uint8_t i = 0; i < n; i++)
{
TP_Point t = touch.getPoint(i);
Serial.printf("[%d] point x: %d point y: %d \r\n", i, t.x, t.y);
}
}
}

View File

@ -0,0 +1,4 @@
# These are supported funding model platforms
github: moononournation
custom: "https://paypal.me/moononournation"

View File

@ -0,0 +1,14 @@
Matt Conte <zeus@ztnet.com>
Just about everything
Neil Stevens <neil@qualityassistant.com>
SDL, automake, current maintainer
Firebug <firebug@cfl.rr.com>
mapper support, testing
Benjamin C. W. Sittler <bsittler@nmt.edu>
config code
The Mighty Mike Master <melanson@pcisys.net>
mapper 231 code

View File

@ -0,0 +1,491 @@
GNU LIBRARY GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1991 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the library GPL. It is
numbered 2 because it goes with version 2 of the ordinary GPL.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Library General Public License, applies to some
specially designated Free Software Foundation software, and to any
other libraries whose authors decide to use it. You can use it for
your libraries, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if
you distribute copies of the library, or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link a program with the library, you must provide
complete object files to the recipients so that they can relink them
with the library, after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
Our method of protecting your rights has two steps: (1) copyright
the library, and (2) offer you this license which gives you legal
permission to copy, distribute and/or modify the library.
Also, for each distributor's protection, we want to make certain
that everyone understands that there is no warranty for this free
library. If the library is modified by someone else and passed on, we
want its recipients to know that what they have is not the original
version, so that any problems introduced by others will not reflect on
the original authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that companies distributing free
software will individually obtain patent licenses, thus in effect
transforming the program into proprietary software. To prevent this,
we have made it clear that any patent must be licensed for everyone's
free use or not licensed at all.
Most GNU software, including some libraries, is covered by the ordinary
GNU General Public License, which was designed for utility programs. This
license, the GNU Library General Public License, applies to certain
designated libraries. This license is quite different from the ordinary
one; be sure to read it in full, and don't assume that anything in it is
the same as in the ordinary license.
The reason we have a separate public license for some libraries is that
they blur the distinction we usually make between modifying or adding to a
program and simply using it. Linking a program with a library, without
changing the library, is in some sense simply using the library, and is
analogous to running a utility program or application program. However, in
a textual and legal sense, the linked executable is a combined work, a
derivative of the original library, and the ordinary General Public License
treats it as such.
Because of this blurred distinction, using the ordinary General
Public License for libraries did not effectively promote software
sharing, because most developers did not use the libraries. We
concluded that weaker conditions might promote sharing better.
However, unrestricted linking of non-free programs would deprive the
users of those programs of all benefit from the free status of the
libraries themselves. This Library General Public License is intended to
permit developers of non-free programs to use free libraries, while
preserving your freedom as a user of such programs to change the free
libraries that are incorporated in them. (We have not seen how to achieve
this as regards changes in header files, but we have achieved it as regards
changes in the actual functions of the Library.) The hope is that this
will lead to faster development of free libraries.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, while the latter only
works together with the library.
Note that it is possible for a library to be covered by the ordinary
General Public License rather than by this special one.
GNU LIBRARY GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library which
contains a notice placed by the copyright holder or other authorized
party saying it may be distributed under the terms of this Library
General Public License (also called "this License"). Each licensee is
addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also compile or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
c) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
d) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the source code distributed need not include anything that is normally
distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Library General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change. You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).
To apply these terms, attach the following notices to the library. It is
safest to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.
<one line to give the library's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307 USA.
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
<signature of Ty Coon>, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!

115
lib/arduino-nofrendo/README Normal file
View File

@ -0,0 +1,115 @@
Nofrendo 2.0pre1 - May 5, 2001
Nofrendo (c) Matt Conte
Nofrendo SDL release by Neil Stevens
To compile and install, do configure, then make, then make install
as you would any other GNU automake-using source release. You may
want to try passing --enable-optimize to configure.
SDL 1.2 is required because recent SDL releases can speed nofrendo
a lot on X displays with more colors.
The key to an enjoyable Nofrendo experience is $HOME/.nofrendo. In
there are all the saves, snapshots (still PCX, but that'll be fixed),
and the config.
config is auto-generated, so don't edit it while nofrendo is running.
Do feel free to edit it while nofrendo is not running, however. Comments
are not preserved, but the data is preserved. The enum in src/event.h is
of interest to those who want to configure their joysticks and keyboard
input.
Nope, it's not easy to configure yet, but that will come in time. This
release is long overdue, so a nice UI will have to wait for a later
release.
In the meantime, here are the default controls, and some hints for
joystick configuration. Forgive if they are unclear, for this is hastily
done, and will be improved later.
(KP means numeric keypad. non-KP numbers refer to the numbers above the
letters on a standard keyboard)
Esc - quit
F1 - soft reset
F2 - hard reset
F3 - toggle FPS display
F4 - take snapshot
F6 - toggle sprites
F10 - toggle fullscreen
Pause - Pause emulation
Space - toggle GUI
KP+ - toggle speed regulation
0-9 - set save state 0-9
F5 - save state
F7 - load state
Backspace - display information
q - toggle sound channel 0
w - toggle sound channel 1
e - toggle sound channel 2
r - toggle sound channel 3
t - toggle sound channel 4
y - toggle sound channel 5
a - toggle wave display
s - sound filter off
d - sound filter mode 1
f - sound filter mode 2
KP2 - Joypad 1 down
Down - Joypad 1 down
KP4 - Joypad 1 left
Left - Joypad 1 left
KP6 - Joypad 1 right
Right - Joypad 1 right
KP8 - Joypad 1 up
Up - Joypad 1 up
Return - Joypad 1 Start
Tab - Joypad 1 Select
z - Joypad 1 b
x - Joypad 1 a
c - Joypad 1 Select
v - Joypad 1 Start
Ctrl - Joypad 1 b
Alt - Joypad 1 a
Shift - Joypad 1 a
b - Joypad 2 b
n - Joypad 2 a
m - Joypad 2 Select
, - Joypad 2 Start
Here's an excerpt from Neil's config, for use with an SNES pad:
[sdljoystick0]
button0=45
button1=46
button2=0
button3=0
button4=0
button5=0
button6=48
button7=47
negativeaxis0=51
negativeaxis1=49
positiveaxis0=52
positiveaxis1=50
Your joystick probably varies, so here are the numbers to use, if you're not
comfortable with reading the C code to find them out:
45 - Joypad 1 a
46 - Joypad 1 b
47 - Joypad 1 start
48 - Joypad 1 select
49 - Joypad 1 right
50 - Joypad 1 down
51 - Joypad 1 left
52 - Joypad 1 right

View File

@ -0,0 +1,13 @@
# arduino-nofrendo
This is a special nofrendo version as a Arduino library.
## Implementation
Simple implement all function definded in osd.h to make it work.
Any Arduino platform that have enough processing power should work.
## Examples
- esp32-nofrendo.ino in examples folder is rewritten from https://github.com/espressif/esp32-nesemu.git

View File

@ -0,0 +1,287 @@
#include <Arduino.h>
#include "hw_config.h"
/* controller is GPIO */
#if defined(HW_CONTROLLER_GPIO)
extern "C" void controller_init()
{
#if defined(HW_CONTROLLER_GPIO_ANALOG_JOYSTICK)
pinMode(HW_CONTROLLER_GPIO_UP_DOWN, INPUT);
pinMode(HW_CONTROLLER_GPIO_LEFT_RIGHT, INPUT);
#else /* !defined(HW_CONTROLLER_GPIO_ANALOG_JOYSTICK) */
pinMode(HW_CONTROLLER_GPIO_UP, INPUT_PULLUP);
pinMode(HW_CONTROLLER_GPIO_DOWN, INPUT_PULLUP);
pinMode(HW_CONTROLLER_GPIO_LEFT, INPUT_PULLUP);
pinMode(HW_CONTROLLER_GPIO_RIGHT, INPUT_PULLUP);
#endif /* !defined(HW_CONTROLLER_GPIO_ANALOG_JOYSTICK) */
pinMode(HW_CONTROLLER_GPIO_SELECT, INPUT_PULLUP);
pinMode(HW_CONTROLLER_GPIO_START, INPUT_PULLUP);
pinMode(HW_CONTROLLER_GPIO_A, INPUT_PULLUP);
pinMode(HW_CONTROLLER_GPIO_B, INPUT_PULLUP);
pinMode(HW_CONTROLLER_GPIO_X, INPUT_PULLUP);
pinMode(HW_CONTROLLER_GPIO_Y, INPUT_PULLUP);
}
extern "C" uint32_t controller_read_input()
{
uint32_t u, d, l, r, s, t, a, b, x, y;
#if defined(HW_CONTROLLER_GPIO_ANALOG_JOYSTICK)
#if defined(HW_CONTROLLER_GPIO_REVERSE_UP)
int joyY = 4095 - analogRead(HW_CONTROLLER_GPIO_UP_DOWN);
#else /* !defined(HW_CONTROLLER_GPIO_REVERSE_UD) */
int joyY = analogRead(HW_CONTROLLER_GPIO_UP_DOWN);
#endif /* !defined(HW_CONTROLLER_GPIO_REVERSE_UD) */
#if defined(HW_CONTROLLER_GPIO_REVERSE_LF)
int joyX = 4095 - analogRead(HW_CONTROLLER_GPIO_LEFT_RIGHT);
#else /* !defined(HW_CONTROLLER_GPIO_REVERSE_LF) */
int joyX = analogRead(HW_CONTROLLER_GPIO_LEFT_RIGHT);
#endif /* !defined(HW_CONTROLLER_GPIO_REVERSE_LF) */
// Serial.printf("joyX: %d, joyY: %d\n", joyX, joyY);
#if defined(ARDUINO_ODROID_ESP32)
if (joyY > 2048 + 1024)
{
u = 0;
d = 1;
}
else if (joyY > 1024)
{
u = 1;
d = 0;
}
else
{
u = 1;
d = 1;
}
if (joyX > 2048 + 1024)
{
l = 0;
r = 1;
}
else if (joyX > 1024)
{
l = 1;
r = 0;
}
else
{
l = 1;
r = 1;
}
#else /* !defined(ARDUINO_ODROID_ESP32) */
if (joyY > 2048 + 1024)
{
u = 1;
d = 0;
}
else if (joyY < 1024)
{
u = 0;
d = 1;
}
else
{
u = 1;
d = 1;
}
if (joyX > 2048 + 1024)
{
l = 1;
r = 0;
}
else if (joyX < 1024)
{
l = 0;
r = 1;
}
else
{
l = 1;
r = 1;
}
#endif /* !defined(ARDUINO_ODROID_ESP32) */
#else /* !defined(HW_CONTROLLER_GPIO_ANALOG_JOYSTICK) */
u = digitalRead(HW_CONTROLLER_GPIO_UP);
d = digitalRead(HW_CONTROLLER_GPIO_DOWN);
l = digitalRead(HW_CONTROLLER_GPIO_LEFT);
r = digitalRead(HW_CONTROLLER_GPIO_RIGHT);
#endif /* !defined(HW_CONTROLLER_GPIO_ANALOG_JOYSTICK) */
s = digitalRead(HW_CONTROLLER_GPIO_SELECT);
t = digitalRead(HW_CONTROLLER_GPIO_START);
a = digitalRead(HW_CONTROLLER_GPIO_A);
b = digitalRead(HW_CONTROLLER_GPIO_B);
x = digitalRead(HW_CONTROLLER_GPIO_X);
y = digitalRead(HW_CONTROLLER_GPIO_Y);
return 0xFFFFFFFF ^ ((!u << 0) | (!d << 1) | (!l << 2) | (!r << 3) | (!s << 4) | (!t << 5) | (!a << 6) | (!b << 7) | (!x << 8) | (!y << 9));
}
/* controller is I2C M5Stack CardKB */
#elif defined(HW_CONTROLLER_I2C_M5CARDKB)
#include <Wire.h>
#define I2C_M5CARDKB_ADDR 0x5f
#define READ_BIT I2C_MASTER_READ /*!< I2C master read */
#define ACK_CHECK_EN 0x1 /*!< I2C master will check ack from slave */
#define NACK_VAL 0x1 /*!< I2C nack value */
extern "C" void controller_init()
{
Wire.begin();
}
extern "C" uint32_t controller_read_input()
{
uint32_t value = 0xFFFFFFFF;
Wire.requestFrom(I2C_M5CARDKB_ADDR, 1);
while (Wire.available())
{
char c = Wire.read(); // receive a byte as characterif
if (c != 0)
{
switch (c)
{
case 181: // up
value ^= (1 << 0);
break;
case 182: // down
value ^= (1 << 1);
break;
case 180: // left
value ^= (1 << 2);
break;
case 183: // right
value ^= (1 << 3);
break;
case ' ': // select
value ^= (1 << 4);
break;
case 13: // enter -> start
value ^= (1 << 5);
break;
case 'k': // A
value ^= (1 << 6);
break;
case 'l': // B
value ^= (1 << 7);
break;
case 'o': // X
value ^= (1 << 8);
break;
case 'p': // Y
value ^= (1 << 9);
break;
}
}
}
return value;
}
/* controller is I2C BBQ10Keyboard */
#elif defined(HW_CONTROLLER_I2C_BBQ10KB)
#include <Wire.h>
#include <BBQ10Keyboard.h>
BBQ10Keyboard keyboard;
static uint32_t value = 0xFFFFFFFF;
extern "C" void controller_init()
{
Wire.begin();
keyboard.begin();
keyboard.setBacklight(0.2f);
}
extern "C" uint32_t controller_read_input()
{
int keyCount = keyboard.keyCount();
while (keyCount--)
{
const BBQ10Keyboard::KeyEvent key = keyboard.keyEvent();
String state = "pressed";
if (key.state == BBQ10Keyboard::StateLongPress)
state = "held down";
else if (key.state == BBQ10Keyboard::StateRelease)
state = "released";
// Serial.printf("key: '%c' (dec %d, hex %02x) %s\r\n", key.key, key.key, key.key, state.c_str());
uint32_t bit = 0;
if (key.key != 0)
{
switch (key.key)
{
case 'w': // up
bit = (1 << 0);
break;
case 'z': // down
bit = (1 << 1);
break;
case 'a': // left
bit = (1 << 2);
break;
case 'd': // right
bit = (1 << 3);
break;
case ' ': // select
bit = (1 << 4);
break;
case 10: // enter -> start
bit = (1 << 5);
break;
case 'k': // A
bit = (1 << 6);
break;
case 'l': // B
bit = (1 << 7);
break;
case 'o': // X
bit = (1 << 8);
break;
case 'p': // Y
bit = (1 << 9);
break;
}
if (key.state == BBQ10Keyboard::StatePress)
{
value ^= bit;
}
else if (key.state == BBQ10Keyboard::StateRelease)
{
value |= bit;
}
}
}
return value;
}
#else /* no controller defined */
extern "C" void controller_init()
{
Serial.printf("GPIO controller disabled in menuconfig; no input enabled.\n");
}
extern "C" uint32_t controller_read_input()
{
return 0xFFFFFFFF;
}
#endif /* no controller defined */

View File

@ -0,0 +1,4 @@
This is an example game that is developed for my article Programming NES games in C. The article itself is located at my website in the Articles section, to make things simpler in case of possible updates.
http://shiru.untergrund.net
mailto:shiru@mail.ru

View File

@ -0,0 +1,174 @@
extern "C"
{
#include <nes/nes.h>
}
#include "hw_config.h"
#include <Arduino_GFX_Library.h>
#define TFT_BRIGHTNESS 128 /* 0 - 255 */
/* M5Stack */
#if defined(ARDUINO_M5Stack_Core_ESP32) || defined(ARDUINO_M5STACK_FIRE)
#define TFT_BL 32
Arduino_ESP32SPI_DMA *bus = new Arduino_ESP32SPI_DMA(27 /* DC */, 14 /* CS */, SCK, MOSI, MISO);
Arduino_ILI9341_M5STACK *gfx = new Arduino_ILI9341_M5STACK(bus, 33 /* RST */, 1 /* rotation */);
/* Odroid-Go */
#elif defined(ARDUINO_ODROID_ESP32)
#define TFT_BL 14
Arduino_ESP32SPI_DMA *bus = new Arduino_ESP32SPI_DMA(21 /* DC */, 5 /* CS */, SCK, MOSI, MISO);
Arduino_ILI9341 *gfx = new Arduino_ILI9341(bus, -1 /* RST */, 3 /* rotation */);
/* TTGO T-Watch */
#elif defined(ARDUINO_T) || defined(ARDUINO_TWATCH_BASE) || defined(ARDUINO_TWATCH_2020_V1) || defined(ARDUINO_TWATCH_2020_V2) // TTGO T-Watch
#define TFT_BL 12
Arduino_DataBus *bus = new Arduino_ESP32SPI_DMA(27 /* DC */, 5 /* CS */, 18 /* SCK */, 19 /* MOSI */, -1 /* MISO */);
Arduino_ST7789 *gfx = new Arduino_ST7789(bus, -1 /* RST */, 1 /* rotation */, true /* IPS */, 240, 240, 0, 80);
/* custom hardware */
#else
/* ST7789 ODROID Compatible pin connection */
// #define TFT_BL 14
// Arduino_ESP32SPI_DMA *bus = new Arduino_ESP32SPI_DMA(21 /* DC */, 5 /* CS */, SCK, MOSI, MISO);
// Arduino_ST7789 *gfx = new Arduino_ST7789(bus, -1 /* RST */, 1 /* rotation */, true /* IPS */);
/* ST7796 on breadboard */
// #define TFT_BL 32
Arduino_DataBus *bus = new Arduino_ESP32SPI_DMA(32 /* DC */, -1 /* CS */, 25 /* SCK */, 33 /* MOSI */, -1 /* MISO */);
Arduino_TFT *gfx = new Arduino_ST7796(bus, -1 /* RST */, 1 /* rotation */);
/* ST7796 on LCDKit */
// #define TFT_BL 23
// Arduino_ESP32SPI_DMA *bus = new Arduino_ESP32SPI_DMA(19 /* DC */, 5 /* CS */, 22 /* SCK */, 21 /* MOSI */, -1 /* MISO */);
// Arduino_ST7796 *gfx = new Arduino_ST7796(bus, 18, 1 /* rotation */);
#endif /* custom hardware */
static int16_t w, h, frame_x, frame_y, frame_x_offset, frame_width, frame_height, frame_line_pixels;
extern int16_t bg_color;
extern uint16_t myPalette[];
extern "C" void display_init()
{
w = gfx->width();
h = gfx->height();
if (w < 480) // assume only 240x240 or 320x240
{
if (w > NES_SCREEN_WIDTH)
{
frame_x = (w - NES_SCREEN_WIDTH) / 2;
frame_x_offset = 0;
frame_width = NES_SCREEN_WIDTH;
frame_height = NES_SCREEN_HEIGHT;
frame_line_pixels = frame_width;
}
else
{
frame_x = 0;
frame_x_offset = (NES_SCREEN_WIDTH - w) / 2;
frame_width = w;
frame_height = NES_SCREEN_HEIGHT;
frame_line_pixels = frame_width;
}
frame_y = (gfx->height() - NES_SCREEN_HEIGHT) / 2;
}
else // assume 480x320
{
frame_x = 0;
frame_y = 0;
frame_x_offset = 8;
frame_width = w;
frame_height = h;
frame_line_pixels = frame_width / 2;
}
}
extern "C" void display_write_frame(const uint8_t *data[])
{
gfx->startWrite();
if (w < 480)
{
gfx->writeAddrWindow(frame_x, frame_y, frame_width, frame_height);
for (int32_t i = 0; i < NES_SCREEN_HEIGHT; i++)
{
gfx->writeIndexedPixels((uint8_t *)(data[i] + frame_x_offset), myPalette, frame_line_pixels);
}
}
else
{
/* ST7796 480 x 320 resolution */
/* Option 1:
* crop 256 x 240 to 240 x 214
* then scale up width x 2 and scale up height x 1.5
* repeat a line for every 2 lines
*/
// gfx->writeAddrWindow(frame_x, frame_y, frame_width, frame_height);
// for (int16_t i = 10; i < (10 + 214); i++)
// {
// gfx->writeIndexedPixelsDouble((uint8_t *)(data[i] + 8), myPalette, frame_line_pixels);
// if ((i % 2) == 1)
// {
// gfx->writeIndexedPixelsDouble((uint8_t *)(data[i] + 8), myPalette, frame_line_pixels);
// }
// }
/* Option 2:
* crop 256 x 240 to 240 x 214
* then scale up width x 2 and scale up height x 1.5
* simply blank a line for every 2 lines
*/
int16_t y = 0;
for (int16_t i = 10; i < (10 + 214); i++)
{
gfx->writeAddrWindow(frame_x, y++, frame_width, 1);
gfx->writeIndexedPixelsDouble((uint8_t *)(data[i] + 8), myPalette, frame_line_pixels);
if ((i % 2) == 1)
{
y++; // blank line
}
}
/* Option 3:
* crop 256 x 240 to 240 x 240
* then scale up width x 2 and scale up height x 1.33
* repeat a line for every 3 lines
*/
// gfx->writeAddrWindow(frame_x, frame_y, frame_width, frame_height);
// for (int16_t i = 0; i < 240; i++)
// {
// gfx->writeIndexedPixelsDouble((uint8_t *)(data[i] + 8), myPalette, frame_line_pixels);
// if ((i % 3) == 1)
// {
// gfx->writeIndexedPixelsDouble((uint8_t *)(data[i] + 8), myPalette, frame_line_pixels);
// }
// }
/* Option 4:
* crop 256 x 240 to 240 x 240
* then scale up width x 2 and scale up height x 1.33
* simply blank a line for every 3 lines
*/
// int16_t y = 0;
// for (int16_t i = 0; i < 240; i++)
// {
// gfx->writeAddrWindow(frame_x, y++, frame_width, 1);
// gfx->writeIndexedPixelsDouble((uint8_t *)(data[i] + 8), myPalette, frame_line_pixels);
// if ((i % 3) == 1)
// {
// y++; // blank line
// }
// }
}
gfx->endWrite();
}
extern "C" void display_clear()
{
gfx->fillScreen(bg_color);
}

View File

@ -0,0 +1,99 @@
/* Arduino Nofrendo
* Please check hw_config.h and display.cpp for configuration details
*/
#include <esp_wifi.h>
#include <esp_task_wdt.h>
#include <SD.h>
#include <SD_MMC.h>
#include <SPIFFS.h>
#include <Arduino_GFX_Library.h>
#include "hw_config.h"
extern "C"
{
#include <nofrendo.h>
}
int16_t bg_color;
extern Arduino_TFT *gfx;
void setup()
{
Serial.begin(115200);
// turn off WiFi
esp_wifi_deinit();
// disable Core 0 WDT
TaskHandle_t idle_0 = xTaskGetIdleTaskHandleForCPU(0);
esp_task_wdt_delete(idle_0);
// init display
gfx->begin();
bg_color = gfx->color565(24, 28, 24); // DARK DARK GREY
gfx->fillScreen(bg_color);
#ifdef TFT_BL
// turn display backlight on
ledcAttachPin(TFT_BL, 1); // assign TFT_BL pin to channel 1
ledcSetup(1, 12000, 8); // 12 kHz PWM, 8-bit resolution
ledcWrite(1, TFT_BRIGHTNESS); // brightness 0 - 255
#endif
// filesystem defined in hw_config.h
FILESYSTEM_BEGIN
// find first rom file (*.nes)
File root = filesystem.open("/");
char *argv[1];
if (!root)
{
Serial.println("Filesystem mount failed! Please check hw_config.h settings.");
gfx->println("Filesystem mount failed! Please check hw_config.h settings.");
}
else
{
bool foundRom = false;
File file = root.openNextFile();
while (file)
{
if (file.isDirectory())
{
// skip
}
else
{
char *filename = (char *)file.name();
int8_t len = strlen(filename);
if (strstr(strlwr(filename + (len - 4)), ".nes"))
{
foundRom = true;
char fullFilename[256];
sprintf(fullFilename, "%s%s", FSROOT, filename);
Serial.println(fullFilename);
argv[0] = fullFilename;
break;
}
}
file = root.openNextFile();
}
if (!foundRom)
{
Serial.println("Failed to find rom file, please copy rom file to data folder and upload with \"ESP32 Sketch Data Upload\"");
argv[0] = "/";
}
Serial.println("NoFrendo start!\n");
nofrendo_main(1, argv);
Serial.println("NoFrendo end!\n");
}
}
void loop()
{
}

View File

@ -0,0 +1,105 @@
#ifndef _HW_CONFIG_H_
#define _HW_CONFIG_H_
#define FSROOT "/fs"
/* M5Stack */
#if defined(ARDUINO_M5Stack_Core_ESP32) || defined(ARDUINO_M5STACK_FIRE)
// Uncomment one of below, M5Stack support SPIFFS and SD
// #define FILESYSTEM_BEGIN SPIFFS.begin(false, FSROOT); FS filesystem = SPIFFS;
#define FILESYSTEM_BEGIN SD.begin(4, SPI, 40000000, FSROOT); FS filesystem = SD;
/* enable audio */
#define HW_AUDIO
/* controller is I2C M5Stack CardKB */
#define HW_CONTROLLER_I2C_M5CARDKB
/* Odroid-Go */
#elif defined(ARDUINO_ODROID_ESP32)
// Uncomment one of below, ODROID support SPIFFS and SD
// #define FILESYSTEM_BEGIN SPIFFS.begin(false, FSROOT); FS filesystem = SPIFFS;
#define FILESYSTEM_BEGIN SD.begin(SS, SPI, 40000000, FSROOT); FS filesystem = SD;
/* enable audio */
#define HW_AUDIO
/* controller is GPIO */
#define HW_CONTROLLER_GPIO
#define HW_CONTROLLER_GPIO_ANALOG_JOYSTICK
#define HW_CONTROLLER_GPIO_UP_DOWN 35
#define HW_CONTROLLER_GPIO_LEFT_RIGHT 34
#define HW_CONTROLLER_GPIO_SELECT 27
#define HW_CONTROLLER_GPIO_START 39
#define HW_CONTROLLER_GPIO_A 32
#define HW_CONTROLLER_GPIO_B 33
#define HW_CONTROLLER_GPIO_X 13
#define HW_CONTROLLER_GPIO_Y 0
/* TTGO T-Watch */
#elif defined(ARDUINO_T) || defined(ARDUINO_TWATCH_BASE) || defined(ARDUINO_TWATCH_2020_V1) || defined(ARDUINO_TWATCH_2020_V2) // TTGO T-Watch
// TTGO T-watch with game module only support SPIFFS
#define FILESYSTEM_BEGIN SPIFFS.begin(false, FSROOT); FS filesystem = SPIFFS;
/* no audio */
/* controller is GPIO */
#define HW_CONTROLLER_GPIO
#define HW_CONTROLLER_GPIO_ANALOG_JOYSTICK
#define HW_CONTROLLER_GPIO_UP_DOWN 34
#define HW_CONTROLLER_GPIO_LEFT_RIGHT 33
#define HW_CONTROLLER_GPIO_SELECT 15
#define HW_CONTROLLER_GPIO_START 36
#define HW_CONTROLLER_GPIO_A 13
#define HW_CONTROLLER_GPIO_B 25
#define HW_CONTROLLER_GPIO_X 14
#define HW_CONTROLLER_GPIO_Y 26
/* custom hardware */
#else
// Uncomment one of below, ESP32 support SPIFFS SD_MMC and SD
/* SPIFFS */
// #define FILESYSTEM_BEGIN SPIFFS.begin(false, FSROOT); FS filesystem = SPIFFS;
/* 1-bit SD mode SD_MMC, always retry once for begin() failed */
// #define FILESYSTEM_BEGIN (!SD_MMC.begin(FSROOT, true)) && (!SD_MMC.begin(FSROOT, true)); FS filesystem = SD_MMC;
/* 4-bit SD mode SD_MMC, always retry once for begin() failed */
// #define FILESYSTEM_BEGIN (!SD_MMC.begin(FSROOT, false)) && (!SD_MMC.begin(FSROOT, false)); FS filesystem = SD_MMC;
/* SD using default SPI settings */
// #define FILESYSTEM_BEGIN SD.begin(22 /* SS */, SPI, 8000000, FSROOT); FS filesystem = SD;
/* SD using custom SPI settings */
#define FILESYSTEM_BEGIN SPIClass spi = SPIClass(HSPI); spi.begin(14, 2, 15, 13); SD.begin(13, spi, 8000000, FSROOT); FS filesystem = SD;
// enable audio
#define HW_AUDIO
#define HW_AUDIO_EXTDAC
#define HW_AUDIO_EXTDAC_WCLK 21
#define HW_AUDIO_EXTDAC_BCLK 22
#define HW_AUDIO_EXTDAC_DOUT 19
/* controller is GPIO */
#define HW_CONTROLLER_GPIO
#define HW_CONTROLLER_GPIO_ANALOG_JOYSTICK
// #define HW_CONTROLLER_GPIO_REVERSE_UD
#define HW_CONTROLLER_GPIO_UP_DOWN 34
#define HW_CONTROLLER_GPIO_REVERSE_LF
#define HW_CONTROLLER_GPIO_LEFT_RIGHT 35
#define HW_CONTROLLER_GPIO_SELECT 27
#define HW_CONTROLLER_GPIO_START 26
#define HW_CONTROLLER_GPIO_A 5
#define HW_CONTROLLER_GPIO_B 4
#define HW_CONTROLLER_GPIO_X 23
#define HW_CONTROLLER_GPIO_Y 18
/* controller is I2C M5Stack CardKB */
// #define HW_CONTROLLER_I2C_M5CARDKB
/* controller is I2C BBQ10Keyboard */
// #define HW_CONTROLLER_I2C_BBQ10KB
#endif /* custom hardware */
#endif /* _HW_CONFIG_H_ */

View File

@ -0,0 +1,378 @@
/* start rewrite from: https://github.com/espressif/esp32-nesemu.git */
#include <freertos/FreeRTOS.h>
#include <freertos/timers.h>
#include <freertos/task.h>
#include <freertos/queue.h>
#include <driver/i2s.h>
#include <esp_heap_caps.h>
#include <noftypes.h>
#include <event.h>
#include <gui.h>
#include <log.h>
#include <nes/nes.h>
#include <nes/nes_pal.h>
#include <nes/nesinput.h>
#include <nofconfig.h>
#include <osd.h>
#include "hw_config.h"
TimerHandle_t timer;
/* memory allocation */
extern void *mem_alloc(int size, bool prefer_fast_memory)
{
if (prefer_fast_memory)
{
return heap_caps_malloc(size, MALLOC_CAP_8BIT);
}
else
{
return heap_caps_malloc_prefer(size, MALLOC_CAP_SPIRAM, MALLOC_CAP_DEFAULT);
}
}
/* audio */
#define DEFAULT_SAMPLERATE 22050
#if defined(HW_AUDIO)
#define DEFAULT_FRAGSIZE 1024
static void (*audio_callback)(void *buffer, int length) = NULL;
QueueHandle_t queue;
static int16_t *audio_frame;
static int osd_init_sound(void)
{
audio_frame = NOFRENDO_MALLOC(4 * DEFAULT_FRAGSIZE);
i2s_config_t cfg = {
#if defined(HW_AUDIO_EXTDAC)
.mode = I2S_MODE_MASTER | I2S_MODE_TX,
#else /* !defined(HW_AUDIO_EXTDAC) */
.mode = I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN,
#endif /* !defined(HW_AUDIO_EXTDAC) */
.sample_rate = DEFAULT_SAMPLERATE,
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
#if defined(HW_AUDIO_EXTDAC)
.communication_format = I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB,
#else /* !defined(HW_AUDIO_EXTDAC) */
.communication_format = I2S_COMM_FORMAT_PCM | I2S_COMM_FORMAT_I2S_MSB,
#endif /* !defined(HW_AUDIO_EXTDAC) */
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
.dma_buf_count = 6,
.dma_buf_len = 512,
.use_apll = false,
};
i2s_driver_install(I2S_NUM_0, &cfg, 2, &queue);
#if defined(HW_AUDIO_EXTDAC)
i2s_pin_config_t pins = {
.bck_io_num = HW_AUDIO_EXTDAC_BCLK,
.ws_io_num = HW_AUDIO_EXTDAC_WCLK,
.data_out_num = HW_AUDIO_EXTDAC_DOUT,
.data_in_num = I2S_PIN_NO_CHANGE,
};
i2s_set_pin(I2S_NUM_0, &pins);
#else /* !defined(HW_AUDIO_EXTDAC) */
i2s_set_pin(I2S_NUM_0, NULL);
i2s_set_dac_mode(I2S_DAC_CHANNEL_BOTH_EN);
#endif /* !defined(HW_AUDIO_EXTDAC) */
i2s_zero_dma_buffer(I2S_NUM_0);
audio_callback = NULL;
return 0;
}
static void osd_stopsound(void)
{
audio_callback = NULL;
}
static void do_audio_frame()
{
int left = DEFAULT_SAMPLERATE / NES_REFRESH_RATE;
while (left)
{
int n = DEFAULT_FRAGSIZE;
if (n > left)
n = left;
audio_callback(audio_frame, n); //get more data
//16 bit mono -> 32-bit (16 bit r+l)
int16_t *mono_ptr = audio_frame + n;
int16_t *stereo_ptr = audio_frame + n + n;
int i = n;
while (i--)
{
#if defined(HW_AUDIO_EXTDAC)
int16_t a = (*(--mono_ptr) >> 2);
*(--stereo_ptr) = a;
*(--stereo_ptr) = a;
#else /* !defined(HW_AUDIO_EXTDAC) */
int16_t a = (*(--mono_ptr) >> 3);
*(--stereo_ptr) = 0x8000 + a;
*(--stereo_ptr) = 0x8000 - a;
#endif /* !defined(HW_AUDIO_EXTDAC) */
}
size_t i2s_bytes_write;
i2s_write(I2S_NUM_0, (const char *)audio_frame, 4 * n, &i2s_bytes_write, portMAX_DELAY);
left -= i2s_bytes_write / 4;
}
}
void osd_setsound(void (*playfunc)(void *buffer, int length))
{
//Indicates we should call playfunc() to get more data.
audio_callback = playfunc;
}
#else /* !defined(HW_AUDIO) */
static int osd_init_sound(void)
{
return 0;
}
static void osd_stopsound(void)
{
}
static void do_audio_frame()
{
}
void osd_setsound(void (*playfunc)(void *buffer, int length))
{
}
#endif /* !defined(HW_AUDIO) */
/* video */
extern void display_init();
extern void display_write_frame(const uint8_t *data[]);
extern void display_clear();
//This runs on core 0.
QueueHandle_t vidQueue;
static void videoTask(void *arg)
{
bitmap_t *bmp = NULL;
while (1)
{
// xQueueReceive(vidQueue, &bmp, portMAX_DELAY); //skip one frame to drop to 30
xQueueReceive(vidQueue, &bmp, portMAX_DELAY);
display_write_frame((const uint8_t **)bmp->line);
}
}
/* get info */
static char fb[1]; //dummy
bitmap_t *myBitmap;
/* initialise video */
static int init(int width, int height)
{
return 0;
}
static void shutdown(void)
{
}
/* set a video mode */
static int set_mode(int width, int height)
{
return 0;
}
/* copy nes palette over to hardware */
uint16 myPalette[256];
static void set_palette(rgb_t *pal)
{
uint16 c;
int i;
for (i = 0; i < 256; i++)
{
c = (pal[i].b >> 3) + ((pal[i].g >> 2) << 5) + ((pal[i].r >> 3) << 11);
//myPalette[i]=(c>>8)|((c&0xff)<<8);
myPalette[i] = c;
}
}
/* clear all frames to a particular color */
static void clear(uint8 color)
{
// SDL_FillRect(mySurface, 0, color);
display_clear();
}
/* acquire the directbuffer for writing */
static bitmap_t *lock_write(void)
{
// SDL_LockSurface(mySurface);
myBitmap = bmp_createhw((uint8 *)fb, NES_SCREEN_WIDTH, NES_SCREEN_HEIGHT, NES_SCREEN_WIDTH * 2);
return myBitmap;
}
/* release the resource */
static void free_write(int num_dirties, rect_t *dirty_rects)
{
bmp_destroy(&myBitmap);
}
static void custom_blit(bitmap_t *bmp, int num_dirties, rect_t *dirty_rects)
{
xQueueSend(vidQueue, &bmp, 0);
do_audio_frame();
}
viddriver_t sdlDriver =
{
"Simple DirectMedia Layer", /* name */
init, /* init */
shutdown, /* shutdown */
set_mode, /* set_mode */
set_palette, /* set_palette */
clear, /* clear */
lock_write, /* lock_write */
free_write, /* free_write */
custom_blit, /* custom_blit */
false /* invalidate flag */
};
void osd_getvideoinfo(vidinfo_t *info)
{
info->default_width = NES_SCREEN_WIDTH;
info->default_height = NES_SCREEN_HEIGHT;
info->driver = &sdlDriver;
}
void osd_getsoundinfo(sndinfo_t *info)
{
info->sample_rate = DEFAULT_SAMPLERATE;
info->bps = 16;
}
/* input */
extern void controller_init();
extern uint32_t controller_read_input();
static void osd_initinput()
{
controller_init();
}
static void osd_freeinput(void)
{
}
void osd_getinput(void)
{
const int ev[32] = {
event_joypad1_up, event_joypad1_down, event_joypad1_left, event_joypad1_right,
event_joypad1_select, event_joypad1_start, event_joypad1_a, event_joypad1_b,
event_state_save, event_state_load, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0};
static int oldb = 0xffff;
uint32_t b = controller_read_input();
uint32_t chg = b ^ oldb;
int x;
oldb = b;
event_t evh;
// nofrendo_log_printf("Input: %x\n", b);
for (x = 0; x < 16; x++)
{
if (chg & 1)
{
evh = event_get(ev[x]);
if (evh)
evh((b & 1) ? INP_STATE_BREAK : INP_STATE_MAKE);
}
chg >>= 1;
b >>= 1;
}
}
void osd_getmouse(int *x, int *y, int *button)
{
}
/* init / shutdown */
static int logprint(const char *string)
{
return printf("%s", string);
}
int osd_init()
{
nofrendo_log_chain_logfunc(logprint);
if (osd_init_sound())
return -1;
display_init();
vidQueue = xQueueCreate(1, sizeof(bitmap_t *));
// xTaskCreatePinnedToCore(&videoTask, "videoTask", 2048, NULL, 5, NULL, 1);
xTaskCreatePinnedToCore(&videoTask, "videoTask", 2048, NULL, 0, NULL, 0);
osd_initinput();
return 0;
}
void osd_shutdown()
{
osd_stopsound();
osd_freeinput();
}
char configfilename[] = "na";
int osd_main(int argc, char *argv[])
{
config.filename = configfilename;
return main_loop(argv[0], system_autodetect);
}
//Seemingly, this will be called only once. Should call func with a freq of frequency,
int osd_installtimer(int frequency, void *func, int funcsize, void *counter, int countersize)
{
nofrendo_log_printf("Timer install, configTICK_RATE_HZ=%d, freq=%d\n", configTICK_RATE_HZ, frequency);
timer = xTimerCreate("nes", configTICK_RATE_HZ / frequency, pdTRUE, NULL, func);
xTimerStart(timer, 0);
return 0;
}
/* filename manipulation */
void osd_fullname(char *fullname, const char *shortname)
{
strncpy(fullname, shortname, PATH_MAX);
}
/* This gives filenames for storage of saves */
char *osd_newextension(char *string, char *ext)
{
// dirty: assume both extensions is 3 characters
size_t l = strlen(string);
string[l - 3] = ext[1];
string[l - 2] = ext[2];
string[l - 1] = ext[3];
return string;
}
/* This gives filenames for storage of PCX snapshots */
int osd_makesnapname(char *filename, int len)
{
return -1;
}

View File

@ -0,0 +1,7 @@
name=arduino-nofrendo
version=1.2
author=Matt Conte <zeus@ztnet.com>, Neil Stevens <neil@qualityassistant.com>, Firebug <firebug@cfl.rr.com>, Benjamin C. W. Sittler <bsittler@nmt.edu>, The Mighty Mike Master <melanson@pcisys.net>
maintainer=Moon On Our Nation <moononournation@gmail.com>
sentence=Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com)
paragraph=This is a special nofrendo version as a Arduino library.
url=https://github.com/moononournation/arduino-nofrendo

View File

@ -0,0 +1,155 @@
/*
** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com)
**
**
** This program is free software; you can redistribute it and/or
** modify it under the terms of version 2 of the GNU Library General
** Public License as published by the Free Software Foundation.
**
** This program 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
** Library General Public License for more details. To obtain a
** copy of the GNU Library General Public License, write to the Free
** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
**
** Any permitted reproduction of these routines, in whole or in part,
** must bear this legend.
**
**
** bitmap.c
**
** Bitmap object manipulation routines
** $Id: bitmap.c,v 1.2 2001/04/27 14:37:11 neil Exp $
*/
#include <stdio.h>
#include <string.h>
#include "noftypes.h"
#include "bitmap.h"
void bmp_clear(const bitmap_t *bitmap, uint8 color)
{
memset(bitmap->data, color, bitmap->pitch * bitmap->height);
}
static bitmap_t *_make_bitmap(uint8 *data_addr, bool hw, int width,
int height, int pitch, int overdraw)
{
bitmap_t *bitmap;
int i;
/* quick safety check */
if (NULL == data_addr)
return NULL;
/* Make sure to add in space for line pointers */
bitmap = NOFRENDO_MALLOC(sizeof(bitmap_t) + (sizeof(uint8 *) * height));
if (NULL == bitmap)
return NULL;
bitmap->hardware = hw;
bitmap->height = height;
bitmap->width = width;
bitmap->data = data_addr;
bitmap->pitch = pitch + (overdraw * 2);
/* Set up line pointers */
/* we want to make some 32-bit aligned adjustment
** if we haven't been given a hardware bitmap
*/
if (false == bitmap->hardware)
{
bitmap->pitch = (bitmap->pitch + 3) & ~3;
bitmap->line[0] = (uint8 *)(((uint32)bitmap->data + overdraw + 3) & ~3);
}
else
{
bitmap->line[0] = bitmap->data + overdraw;
}
for (i = 1; i < height; i++)
bitmap->line[i] = bitmap->line[i - 1] + bitmap->pitch;
return bitmap;
}
/* Allocate and initialize a bitmap structure */
bitmap_t *bmp_create(int width, int height, int overdraw)
{
uint8 *addr;
int pitch;
pitch = width + (overdraw * 2); /* left and right */
addr = NOFRENDO_MALLOC((pitch * height) + 3); /* add max 32-bit aligned adjustment */
if (NULL == addr)
return NULL;
return _make_bitmap(addr, false, width, height, width, overdraw);
}
/* allocate and initialize a hardware bitmap */
bitmap_t *bmp_createhw(uint8 *addr, int width, int height, int pitch)
{
return _make_bitmap(addr, true, width, height, pitch, 0); /* zero overdraw */
}
/* Deallocate space for a bitmap structure */
void bmp_destroy(bitmap_t **bitmap)
{
if (*bitmap)
{
if ((*bitmap)->data && false == (*bitmap)->hardware)
NOFRENDO_FREE((*bitmap)->data);
NOFRENDO_FREE(*bitmap);
*bitmap = NULL;
}
}
/*
** $Log: bitmap.c,v $
** Revision 1.2 2001/04/27 14:37:11 neil
** wheeee
**
** Revision 1.1.1.1 2001/04/27 07:03:54 neil
** initial
**
** Revision 1.16 2000/11/05 16:37:18 matt
** rolled rgb.h into bitmap.h
**
** Revision 1.15 2000/10/10 13:58:13 matt
** stroustrup squeezing his way in the door
**
** Revision 1.14 2000/09/18 02:06:48 matt
** -pedantic is your friend
**
** Revision 1.13 2000/08/13 13:16:30 matt
** bugfix for alignment adjustment
**
** Revision 1.12 2000/07/24 04:31:43 matt
** pitch/data area on non-hw bitmaps get padded to 32-bit boundaries
**
** Revision 1.11 2000/07/17 01:52:27 matt
** made sure last line of all source files is a newline
**
** Revision 1.10 2000/07/09 14:43:01 matt
** pitch is now configurable for bmp_createhw()
**
** Revision 1.9 2000/07/06 17:55:57 matt
** two big bugs fixed
**
** Revision 1.8 2000/07/06 17:38:11 matt
** replaced missing string.h include
**
** Revision 1.7 2000/07/06 16:46:57 matt
** added bmp_clear() routine
**
** Revision 1.6 2000/06/26 04:56:24 matt
** minor cleanup
**
** Revision 1.5 2000/06/09 15:12:25 matt
** initial revision
**
*/

View File

@ -0,0 +1,93 @@
/*
** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com)
**
**
** This program is free software; you can redistribute it and/or
** modify it under the terms of version 2 of the GNU Library General
** Public License as published by the Free Software Foundation.
**
** This program 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
** Library General Public License for more details. To obtain a
** copy of the GNU Library General Public License, write to the Free
** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
**
** Any permitted reproduction of these routines, in whole or in part,
** must bear this legend.
**
**
** bitmap.h
**
** Bitmap object defines / prototypes
** $Id: bitmap.h,v 1.2 2001/04/27 14:37:11 neil Exp $
*/
#ifndef _BITMAP_H_
#define _BITMAP_H_
#include "noftypes.h"
/* a bitmap rectangle */
typedef struct rect_s
{
int16 x, y;
uint16 w, h;
} rect_t;
typedef struct rgb_s
{
int r, g, b;
} rgb_t;
typedef struct bitmap_s
{
int width, height, pitch;
bool hardware; /* is data a hardware region? */
uint8 *data; /* protected */
uint8 *line[ZERO_LENGTH]; /* will hold line pointers */
} bitmap_t;
extern void bmp_clear(const bitmap_t *bitmap, uint8 color);
extern bitmap_t *bmp_create(int width, int height, int overdraw);
extern bitmap_t *bmp_createhw(uint8 *addr, int width, int height, int pitch);
extern void bmp_destroy(bitmap_t **bitmap);
#endif /* _BITMAP_H_ */
/*
** $Log: bitmap.h,v $
** Revision 1.2 2001/04/27 14:37:11 neil
** wheeee
**
** Revision 1.1.1.1 2001/04/27 07:03:54 neil
** initial
**
** Revision 1.12 2000/11/05 16:37:18 matt
** rolled rgb.h into bitmap.h
**
** Revision 1.11 2000/10/10 13:58:13 matt
** stroustrup squeezing his way in the door
**
** Revision 1.10 2000/09/18 02:06:48 matt
** -pedantic is your friend
**
** Revision 1.9 2000/07/31 04:28:46 matt
** one million cleanups
**
** Revision 1.8 2000/07/24 04:31:43 matt
** pitch/data area on non-hw bitmaps get padded to 32-bit boundaries
**
** Revision 1.7 2000/07/17 01:52:27 matt
** made sure last line of all source files is a newline
**
** Revision 1.6 2000/07/09 14:43:01 matt
** pitch is now configurable for bmp_createhw()
**
** Revision 1.5 2000/07/06 16:46:57 matt
** added bmp_clear() routine
**
** Revision 1.4 2000/06/09 15:12:25 matt
** initial revision
**
*/

View File

@ -0,0 +1,456 @@
/* Nofrendo Configuration Braindead Sample Implementation
**
** $Id: config.c,v 1.2 2001/04/27 14:37:11 neil Exp $
*/
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "noftypes.h"
#include "log.h"
#include "osd.h"
#include "nofconfig.h"
#include "version.h"
typedef struct myvar_s
{
struct myvar_s *less, *greater;
char *group, *key, *value;
} myvar_t;
static myvar_t *myVars = NULL;
static bool mySaveNeeded = false;
static void my_destroy(myvar_t **var)
{
ASSERT(*var);
if ((*var)->group)
NOFRENDO_FREE((*var)->group);
if ((*var)->key)
NOFRENDO_FREE((*var)->key);
if ((*var)->value)
NOFRENDO_FREE((*var)->value);
NOFRENDO_FREE(*var);
}
static myvar_t *my_create(const char *group, const char *key, const char *value)
{
myvar_t *var;
var = NOFRENDO_MALLOC(sizeof(*var));
if (NULL == var)
{
return 0;
}
var->less = var->greater = NULL;
var->group = var->key = var->value = NULL;
if ((var->group = NOFRENDO_MALLOC(strlen(group) + 1)) && (var->key = NOFRENDO_MALLOC(strlen(key) + 1)) && (var->value = NOFRENDO_MALLOC(strlen(value) + 1)))
{
strcpy(var->group, group);
strcpy(var->key, key);
strcpy(var->value, value);
return var;
}
my_destroy(&var);
return NULL;
}
static myvar_t *my_lookup(const char *group, const char *key)
{
int cmp;
myvar_t *current = myVars;
while (current && ((cmp = stricmp(group, current->group)) || (cmp = stricmp(key, current->key))))
{
if (cmp < 0)
current = current->less;
else
current = current->greater;
}
return current;
}
static void my_insert(myvar_t *var)
{
int cmp;
myvar_t **current = &myVars;
while (*current && ((cmp = stricmp(var->group, (*current)->group)) || (cmp = stricmp(var->key, (*current)->key))))
{
current = (cmp < 0) ? &(*current)->less : &(*current)->greater;
}
if (*current)
{
var->less = (*current)->less;
var->greater = (*current)->greater;
my_destroy(current);
}
else
{
var->less = var->greater = NULL;
}
*current = var;
}
static void my_save(FILE *stream, myvar_t *var, char **group)
{
if (NULL == var)
return;
my_save(stream, var->less, group);
if (stricmp(*group, var->group))
{
fprintf(stream, "\n[%s]\n", var->group);
*group = var->group;
}
fprintf(stream, "%s=%s\n", var->key, var->value);
my_save(stream, var->greater, group);
}
static void my_cleanup(myvar_t *var)
{
if (NULL == var)
return;
my_cleanup(var->less);
my_cleanup(var->greater);
my_destroy(&var);
}
static char *my_getline(FILE *stream)
{
char buf[1024];
char *dynamic = NULL;
do
{
if (NULL == (fgets(buf, sizeof(buf), stream)))
{
if (dynamic)
NOFRENDO_FREE(dynamic);
return 0;
}
if (NULL == dynamic)
{
dynamic = NOFRENDO_MALLOC(strlen(buf) + 1);
if (NULL == dynamic)
{
return 0;
}
strcpy(dynamic, buf);
}
else
{
/* a mini-version of realloc that works with our memory manager */
char *temp = NULL;
temp = NOFRENDO_MALLOC(strlen(dynamic) + strlen(buf) + 1);
if (NULL == temp)
return 0;
strcpy(temp, dynamic);
NOFRENDO_FREE(dynamic);
dynamic = temp;
strcat(dynamic, buf);
}
if (feof(stream))
{
return dynamic;
}
} while (dynamic[strlen(dynamic) - 1] != '\n');
return dynamic;
}
/* load_config loads from the disk the saved configuration. */
static int load_config(char *filename)
{
FILE *config_file;
if ((config_file = fopen(filename, "r")))
{
char *line;
char *group = NULL, *key = NULL, *value = NULL;
mySaveNeeded = true;
while ((line = my_getline(config_file)))
{
char *s;
if ('\n' == line[strlen(line) - 1])
line[strlen(line) - 1] = '\0';
s = line;
do
{
/* eat up whitespace */
while (isspace(*s))
s++;
switch (*s)
{
case ';':
case '#':
case '\0':
*s = '\0';
break;
case '[':
if (group)
NOFRENDO_FREE(group);
group = ++s;
s = strchr(s, ']');
if (NULL == s)
{
nofrendo_log_printf("load_config: missing ']' after group\n");
s = group + strlen(group);
}
else
{
*s++ = '\0';
}
if ((value = NOFRENDO_MALLOC(strlen(group) + 1)))
{
strcpy(value, group);
}
group = value;
break;
default:
key = s;
s = strchr(s, '=');
if (NULL == s)
{
nofrendo_log_printf("load_config: missing '=' after key\n");
s = key + strlen(key);
}
else
{
*s++ = '\0';
}
while (strlen(key) && isspace(key[strlen(key) - 1]))
key[strlen(key) - 1] = '\0';
while (isspace(*s))
s++;
while (strlen(s) && isspace(s[strlen(s) - 1]))
s[strlen(s) - 1] = '\0';
{
myvar_t *var = my_create(group ? group : "", key, s);
if (NULL == var)
{
nofrendo_log_printf("load_config: my_create failed\n");
return -1;
}
my_insert(var);
}
s += strlen(s);
}
} while (*s);
NOFRENDO_FREE(line);
}
if (group)
NOFRENDO_FREE(group);
fclose(config_file);
}
return 0;
}
/* save_config saves the current configuration to disk.*/
static int save_config(char *filename)
{
FILE *config_file;
char *group = "";
config_file = fopen(filename, "w");
if (NULL == config_file)
{
nofrendo_log_printf("save_config failed\n");
return -1;
}
fprintf(config_file, ";; " APP_STRING " " APP_VERSION "\n");
fprintf(config_file, ";; NOTE: comments are not preserved.\n");
my_save(config_file, myVars, &group);
fclose(config_file);
return 0;
}
static bool open_config(void)
{
return load_config(config.filename);
}
static void close_config(void)
{
if (true == mySaveNeeded)
{
save_config(config.filename);
}
my_cleanup(myVars);
}
static void write_int(const char *group, const char *key, int value)
{
char buf[24];
static myvar_t *var;
sprintf(buf, "%d", value);
buf[sizeof(buf) - 1] = '\0';
var = my_create(group, key, buf);
if (NULL == var)
{
nofrendo_log_printf("write_int failed\n");
return;
}
my_insert(var);
mySaveNeeded = true;
}
/* read_int loads an integer from the configuration into "value"
**
** If the specified "key" does not exist, the "def"ault is returned
*/
static int read_int(const char *group, const char *key, int def)
{
static myvar_t *var;
var = my_lookup(group, key);
if (NULL == var)
{
write_int(group, key, def);
return def;
}
return strtoul(var->value, 0, 0);
}
static void write_string(const char *group, const char *key, const char *value)
{
static myvar_t *var;
var = my_create(group, key, value);
if (NULL == var)
{
nofrendo_log_printf("write_string failed\n");
return;
}
my_insert(var);
mySaveNeeded = true;
}
/* read_string copies a string from the configuration into "value"
**
** If the specified "key" does not exist, the "def"ault is returned
*/
static const char *read_string(const char *group, const char *key, const char *def)
{
static myvar_t *var;
var = my_lookup(group, key);
if (NULL == var)
{
if (def != NULL)
write_string(group, key, def);
return def;
}
return var->value;
}
/* interface */
config_t config =
{
open_config,
close_config,
read_int,
read_string,
write_int,
write_string,
CONFIG_FILE};
/*
** $Log: config.c,v $
** Revision 1.2 2001/04/27 14:37:11 neil
** wheeee
**
** Revision 1.1.1.1 2001/04/27 07:03:54 neil
** initial
**
** Revision 1.14 2000/11/05 06:23:10 matt
** realloc was incompatible with memguard
**
** Revision 1.13 2000/10/10 13:58:13 matt
** stroustrup squeezing his way in the door
**
** Revision 1.12 2000/09/20 01:13:28 matt
** damn tabs
**
** Revision 1.11 2000/08/04 12:41:04 neil
** current not a bug
**
** Revision 1.10 2000/07/31 04:28:46 matt
** one million cleanups
**
** Revision 1.9 2000/07/24 04:30:42 matt
** slight cleanup
**
** Revision 1.8 2000/07/23 15:16:08 matt
** changed strcasecmp to stricmp
**
** Revision 1.7 2000/07/19 15:58:55 neil
** config file now configurable (ha)
**
** Revision 1.6 2000/07/18 03:28:32 matt
** help me! I'm a complete mess!
**
** Revision 1.5 2000/07/12 11:03:08 neil
** Always write a config, even if no defaults are changed
**
** Revision 1.4 2000/07/11 15:09:30 matt
** suppressed all warnings
**
** Revision 1.3 2000/07/11 14:59:27 matt
** minor cosmetics.. =)
**
** Revision 1.2 2000/07/11 13:35:38 bsittler
** Changed the config API, implemented config file "nofrendo.cfg". The
** GGI drivers use the group [GGI]. Visual= and Mode= keys are understood.
**
** Revision 1.1 2000/07/11 09:21:10 bsittler
** This is a skeletal configuration system.
**
*/

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More