lot of cool stuff is working now :D
parent
7ab6afc067
commit
ee784749df
File diff suppressed because one or more lines are too long
@ -1,36 +0,0 @@
|
|||||||
/**
|
|
||||||
* Mocking client-server processing
|
|
||||||
*/
|
|
||||||
|
|
||||||
const _settings = {
|
|
||||||
// connected wifi
|
|
||||||
"wifi_ssid": "",
|
|
||||||
|
|
||||||
// oparation mode
|
|
||||||
"device_mode": "active",
|
|
||||||
|
|
||||||
// Set rotation setting for display
|
|
||||||
// 0 thru 3 corresponding to 4 cardinal rotations
|
|
||||||
"device_rotation": 0,
|
|
||||||
|
|
||||||
// deep sleep timer
|
|
||||||
"cloud_refresh": 97
|
|
||||||
}
|
|
||||||
|
|
||||||
import axios from 'axios'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param cb
|
|
||||||
* @returns {PromiseLike<any> | Promise<any>}
|
|
||||||
*/
|
|
||||||
getSettings(cb) {
|
|
||||||
|
|
||||||
return _settings
|
|
||||||
|
|
||||||
return axios
|
|
||||||
.get('/api/settings')
|
|
||||||
.then(response => cb(response.data))
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,80 @@
|
|||||||
|
/**
|
||||||
|
* Mocking client-server processing
|
||||||
|
*/
|
||||||
|
|
||||||
|
// eslint-disable-next-line
|
||||||
|
const _settings = {
|
||||||
|
// connected wifi
|
||||||
|
"wifi_ssid": "",
|
||||||
|
|
||||||
|
// oparation mode
|
||||||
|
"device_mode": "active",
|
||||||
|
|
||||||
|
// Set rotation setting for display
|
||||||
|
// 0 thru 3 corresponding to 4 cardinal rotations
|
||||||
|
"device_rotation": 0,
|
||||||
|
|
||||||
|
// clound server endpoint
|
||||||
|
"cloud_server": ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line
|
||||||
|
const _wifiScan = [{ "rssi": -59, "ssid": "xd-design.info", "bssid": "38:10:D5:34:80:1B", "channel": 11, "secure": 3 }, { "rssi": -75, "ssid": "FRITZ!Box 7430 JI", "bssid": "38:10:D5:5D:FE:7C", "channel": 1, "secure": 3 }, { "rssi": -87, "ssid": "Vodafone Hotspot", "bssid": "AA:0E:14:BD:50:ED", "channel": 1, "secure": 0 }, { "rssi": -88, "ssid": "WLAN-548426", "bssid": "E0:60:66:55:7F:C5", "channel": 1, "secure": 3 }, { "rssi": -89, "ssid": "Familie Kalinowski", "bssid": "C8:0E:14:BD:50:ED", "channel": 1, "secure": 3 }, { "rssi": -91, "ssid": "WLAN-507287", "bssid": "E0:60:66:48:6C:6B", "channel": 1, "secure": 3 }, { "rssi": -94, "ssid": "TP-LINK_7238", "bssid": "A4:2B:B0:D8:72:38", "channel": 3, "secure": 3 }]
|
||||||
|
|
||||||
|
import axios from 'axios'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param cb
|
||||||
|
* @returns {PromiseLike<any> | Promise<any>}
|
||||||
|
*/
|
||||||
|
getSettings(cb) {
|
||||||
|
return axios
|
||||||
|
.get('/api/settings')
|
||||||
|
.then(response => cb(response.data))
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {IDBRequest<IDBValidKey> | Promise<void>}
|
||||||
|
*/
|
||||||
|
putSettings(settings, cb) {
|
||||||
|
return axios
|
||||||
|
.put('/api/settings', settings, {
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(response => cb(response.data))
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* scan for wifi in range
|
||||||
|
* @param {*} cb
|
||||||
|
*/
|
||||||
|
wifiScan(cb) {
|
||||||
|
return cb(_wifiScan)
|
||||||
|
|
||||||
|
// eslint-disable-next-line
|
||||||
|
return axios
|
||||||
|
.get('/api/wifi/scan')
|
||||||
|
.then(response => cb(response.data))
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
wifiConnect(ssid, password, cb) {
|
||||||
|
return axios
|
||||||
|
.put('/api/wifi/connect', {
|
||||||
|
ssid: ssid,
|
||||||
|
password: password
|
||||||
|
}, {
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(response => cb(response.data))
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,156 @@
|
|||||||
|
<template>
|
||||||
|
<v-layout fluid fill-height>
|
||||||
|
<template v-if="isLoading">
|
||||||
|
<v-overlay :absolute="true" :value="true">
|
||||||
|
<v-progress-circular indeterminate size="64"></v-progress-circular>
|
||||||
|
</v-overlay>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template v-if="true">
|
||||||
|
<v-container>
|
||||||
|
|
||||||
|
<v-snackbar
|
||||||
|
v-model="isSnackbar"
|
||||||
|
:timeout="3000"
|
||||||
|
color="success"
|
||||||
|
>
|
||||||
|
i8n:saved
|
||||||
|
</v-snackbar>
|
||||||
|
|
||||||
|
<v-dialog v-model="wifiConnectModal" max-width="400">
|
||||||
|
<v-card>
|
||||||
|
<v-card-title class="headline">
|
||||||
|
{{ wifiConnectSSID }}
|
||||||
|
</v-card-title>
|
||||||
|
|
||||||
|
<v-card-text>
|
||||||
|
<v-text-field
|
||||||
|
v-model="password"
|
||||||
|
:append-icon="show1 ? 'mdi-eye' : 'mdi-eye-off'"
|
||||||
|
:type="show1 ? 'text' : 'password'"
|
||||||
|
label="i8n:Password"
|
||||||
|
@click:append="show1 = !show1"
|
||||||
|
></v-text-field>
|
||||||
|
</v-card-text>
|
||||||
|
|
||||||
|
<v-card-actions>
|
||||||
|
<v-spacer></v-spacer>
|
||||||
|
<v-btn text @click="wifiConnectModal = false">i8n:Cancel</v-btn>
|
||||||
|
<v-btn color="primary darken-1" text @click="onWifiConnect()">i8n:Connect</v-btn>
|
||||||
|
</v-card-actions>
|
||||||
|
</v-card>
|
||||||
|
</v-dialog>
|
||||||
|
|
||||||
|
<v-card
|
||||||
|
class="mx-auto"
|
||||||
|
max-width="300"
|
||||||
|
tile
|
||||||
|
>
|
||||||
|
<v-list >
|
||||||
|
<v-subheader>Wifi found</v-subheader>
|
||||||
|
<v-list-item-group v-model="wifiConnectSSID" color="primary">
|
||||||
|
<v-list-item
|
||||||
|
v-for="(wifi, i) in wifiAvailable"
|
||||||
|
:key="i"
|
||||||
|
:value="wifi.ssid"
|
||||||
|
@click.stop="wifiConnectModal = true"
|
||||||
|
>
|
||||||
|
<v-list-item-icon>
|
||||||
|
<v-icon v-text="getWifiIcon(wifi)"></v-icon>
|
||||||
|
</v-list-item-icon>
|
||||||
|
<v-list-item-content>
|
||||||
|
<v-list-item-title v-text="wifi.ssid"></v-list-item-title>
|
||||||
|
<v-list-item-subtitle v-text="wifi.bssid"></v-list-item-subtitle>
|
||||||
|
</v-list-item-content>
|
||||||
|
<v-list-item-avatar>
|
||||||
|
<v-avatar color="teal" size="24">
|
||||||
|
<span class="white--text headline caption">{{ wifi.channel }}</span>
|
||||||
|
</v-avatar>
|
||||||
|
</v-list-item-avatar>
|
||||||
|
</v-list-item>
|
||||||
|
</v-list-item-group>
|
||||||
|
</v-list>
|
||||||
|
</v-card>
|
||||||
|
|
||||||
|
</v-container>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
</v-layout>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import apiDevice from '../api/device'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "Settings",
|
||||||
|
data: () => ({
|
||||||
|
isLoading: true,
|
||||||
|
isSnackbar: false,
|
||||||
|
|
||||||
|
wifiAvailable: [],
|
||||||
|
wifiConnectSSID: null,
|
||||||
|
wifiConnectModal: false,
|
||||||
|
show1: false,
|
||||||
|
}),
|
||||||
|
created () {
|
||||||
|
this.$vuetify.icons.values.signalWifi0 = {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/signal_wifi_0_bar/baseline.svg')}
|
||||||
|
this.$vuetify.icons.values.signalWifi1 = {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/signal_wifi_1_bar/baseline.svg')}
|
||||||
|
this.$vuetify.icons.values.signalWifi1Lock = {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/signal_wifi_1_bar_lock/baseline.svg')}
|
||||||
|
this.$vuetify.icons.values.signalWifi2 = {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/signal_wifi_2_bar/baseline.svg')}
|
||||||
|
this.$vuetify.icons.values.signalWifi2Lock = {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/signal_wifi_2_bar_lock/baseline.svg')}
|
||||||
|
this.$vuetify.icons.values.signalWifi3 = {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/signal_wifi_3_bar/baseline.svg')}
|
||||||
|
this.$vuetify.icons.values.signalWifi3Lock = {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/signal_wifi_3_bar_lock/baseline.svg')}
|
||||||
|
this.$vuetify.icons.values.signalWifi4 = {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/signal_wifi_4_bar/baseline.svg')}
|
||||||
|
this.$vuetify.icons.values.signalWifi4Lock = {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/signal_wifi_4_bar_lock/baseline.svg')}
|
||||||
|
|
||||||
|
apiDevice.wifiScan(list => {
|
||||||
|
this.wifiAvailable = list
|
||||||
|
|
||||||
|
this.isLoading = false
|
||||||
|
})
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getWifiIcon(wifi) {
|
||||||
|
let icon = '$signalWifi'
|
||||||
|
|
||||||
|
// strength
|
||||||
|
if (wifi.rssi >= -67) {
|
||||||
|
icon += 4
|
||||||
|
}
|
||||||
|
else if (wifi.rssi >= -70) {
|
||||||
|
icon += 3
|
||||||
|
}
|
||||||
|
else if (wifi.rssi >= -80) {
|
||||||
|
icon += 2
|
||||||
|
}
|
||||||
|
else if (wifi.rssi >= -90) {
|
||||||
|
icon += 1
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
icon += 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// secure
|
||||||
|
if (wifi.secure !== 0 && wifi.rssi >= -90) {
|
||||||
|
icon += 'Lock'
|
||||||
|
}
|
||||||
|
|
||||||
|
return icon
|
||||||
|
},
|
||||||
|
|
||||||
|
onWifiConnect() {
|
||||||
|
// TODO
|
||||||
|
//this.isLoading = true
|
||||||
|
//alert("onWifiConnect")
|
||||||
|
|
||||||
|
//apiDevice.wifiConnect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
@ -1,8 +1,17 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
"outputDir": "../data/dist",
|
"outputDir": "../data/dist",
|
||||||
"filenameHashing": false,
|
"filenameHashing": false,
|
||||||
"productionSourceMap": false,
|
"productionSourceMap": false,
|
||||||
"transpileDependencies": [
|
"transpileDependencies": [
|
||||||
"vuetify"
|
"vuetify"
|
||||||
]
|
],
|
||||||
|
devServer: {
|
||||||
|
proxy: {
|
||||||
|
'^/api': {
|
||||||
|
target: 'http://192.168.178.65:80',
|
||||||
|
ws: true,
|
||||||
|
changeOrigin: true
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,81 +1,85 @@
|
|||||||
#include "device.h"
|
#include "device.h"
|
||||||
|
#include "settings.h"
|
||||||
|
|
||||||
#define uS_TO_S_FACTOR 1000000 /* Conversion factor for micro seconds to seconds */
|
#define uS_TO_S_FACTOR 1000000 /* Conversion factor for micro seconds to seconds */
|
||||||
RTC_DATA_ATTR int bootCount = 0;
|
RTC_DATA_ATTR int bootCount = 0;
|
||||||
RTC_DATA_ATTR long config_DeepSleepInterval = 0;
|
RTC_DATA_ATTR long config_DeepSleepInterval = 10; // sec
|
||||||
|
|
||||||
|
unsigned long bootTime = 0;
|
||||||
|
|
||||||
// private methods
|
// private methods
|
||||||
void sleepDevice();
|
void sleepDevice();
|
||||||
String getWakeupReason();
|
bool isBootTimeOver();
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* setup deep sleep mode
|
* setup deep sleep mode
|
||||||
*/
|
*/
|
||||||
void setupDevice()
|
void setupDevice()
|
||||||
{
|
{
|
||||||
// increment boot number and print it every reboot
|
// increment boot number and print it every reboot
|
||||||
bootCount++;
|
bootCount++;
|
||||||
|
bootTime = millis();
|
||||||
// TODO muss in der cloud passieren? config wakeup timer
|
|
||||||
//deviceSetSleepInterval(300);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void loopDevice()
|
void loopDevice()
|
||||||
{
|
{
|
||||||
if (config_DeepSleepInterval > 0)
|
if (NVS.getString("device_mode") == "passive")
|
||||||
{
|
{
|
||||||
sleepDevice();
|
// TODO give user a time window to switch the mode to active
|
||||||
// device stop here
|
if (true) // isBootTimeOver()
|
||||||
}
|
{
|
||||||
|
sleepDevice();
|
||||||
|
// device stop here
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void sleepDevice()
|
void sleepDevice()
|
||||||
{
|
{
|
||||||
Serial.println("Going to sleep now");
|
Serial.println("Going to sleep now");
|
||||||
Serial.flush();
|
Serial.flush();
|
||||||
|
|
||||||
esp_sleep_enable_timer_wakeup(config_DeepSleepInterval * uS_TO_S_FACTOR);
|
esp_sleep_enable_timer_wakeup(config_DeepSleepInterval * uS_TO_S_FACTOR);
|
||||||
esp_deep_sleep_start();
|
esp_deep_sleep_start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void deviceSetSleepInterval(long interval)
|
void deviceSetSleepInterval(long interval)
|
||||||
{
|
{
|
||||||
config_DeepSleepInterval = interval;
|
config_DeepSleepInterval = interval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
long deviceGetSleepInterval()
|
long deviceGetSleepInterval()
|
||||||
{
|
{
|
||||||
return config_DeepSleepInterval;
|
return config_DeepSleepInterval;
|
||||||
}
|
}
|
||||||
|
|
||||||
String getWakeupReason()
|
bool isBootTimeOver()
|
||||||
{
|
{
|
||||||
esp_sleep_wakeup_cause_t wakeup_reason;
|
return millis() - bootTime >= 60000;
|
||||||
wakeup_reason = esp_sleep_get_wakeup_cause();
|
}
|
||||||
|
|
||||||
//return String(wakeup_reason);
|
|
||||||
|
|
||||||
switch (wakeup_reason)
|
|
||||||
{
|
|
||||||
case 1:
|
|
||||||
return String("Wakeup caused by external signal using RTC_IO");
|
|
||||||
case 2:
|
|
||||||
return String("Wakeup caused by external signal using RTC_CNTL");
|
|
||||||
case 3:
|
|
||||||
return String("Wakeup caused by timer");
|
|
||||||
case 4:
|
|
||||||
return String("Wakeup caused by touchpad");
|
|
||||||
case 5:
|
|
||||||
return String("Wakeup caused by ULP program");
|
|
||||||
default:
|
|
||||||
return String("Wakeup was not caused by deep sleep: " + String(wakeup_reason));
|
|
||||||
}
|
|
||||||
|
|
||||||
return String("unkown");
|
String getWakeupReason()
|
||||||
|
{
|
||||||
|
esp_sleep_wakeup_cause_t wakeup_reason;
|
||||||
|
wakeup_reason = esp_sleep_get_wakeup_cause();
|
||||||
|
|
||||||
|
//return String(wakeup_reason);
|
||||||
|
|
||||||
|
switch (wakeup_reason)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
return String("Wakeup caused by external signal using RTC_IO");
|
||||||
|
case 2:
|
||||||
|
return String("Wakeup caused by external signal using RTC_CNTL");
|
||||||
|
case 3:
|
||||||
|
return String("Wakeup caused by timer");
|
||||||
|
case 4:
|
||||||
|
return String("Wakeup caused by touchpad");
|
||||||
|
case 5:
|
||||||
|
return String("Wakeup caused by ULP program");
|
||||||
|
default:
|
||||||
|
return String("Wakeup was not caused by deep sleep: " + String(wakeup_reason));
|
||||||
|
}
|
||||||
|
|
||||||
|
return String("unkown");
|
||||||
}
|
}
|
@ -0,0 +1,298 @@
|
|||||||
|
#include <Arduino.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint16_t x1;
|
||||||
|
uint16_t y1;
|
||||||
|
uint16_t x2;
|
||||||
|
uint16_t y2;
|
||||||
|
} dispWin_t;
|
||||||
|
|
||||||
|
dispWin_t dispWin = {
|
||||||
|
.x1 = 0,
|
||||||
|
.y1 = 0,
|
||||||
|
.x2 = 640, // DEFAULT_TFT_DISPLAY_WIDTH,
|
||||||
|
.y2 = 384, // DEFAULT_TFT_DISPLAY_HEIGHT,
|
||||||
|
};
|
||||||
|
uint8_t image_debug;
|
||||||
|
|
||||||
|
// @see https://github.com/Bodmer/TJpg_Decoder/blob/master/examples/SPIFFS_Jpg/SPIFFS_Jpg.ino
|
||||||
|
|
||||||
|
// @see https://github.com/loboris/ESP32_TFT_library/blob/aa21772f54a71887ec08b2e8bbaef9e304009891/components/tft/tft.c
|
||||||
|
void TFT_bmp_image(int x, int y, uint8_t scale, char *fname, uint8_t *imgbuf, int size)
|
||||||
|
{
|
||||||
|
FILE *fhndl = NULL;
|
||||||
|
struct stat sb;
|
||||||
|
int i, err=0;
|
||||||
|
int img_xsize, img_ysize, img_xstart, img_xlen, img_ystart, img_ylen;
|
||||||
|
int img_pos, img_pix_pos, scan_lines, rd_len;
|
||||||
|
uint8_t tmpc;
|
||||||
|
uint16_t wtemp;
|
||||||
|
uint32_t temp;
|
||||||
|
int disp_xstart, disp_xend, disp_ystart, disp_yend;
|
||||||
|
uint8_t buf[56];
|
||||||
|
char err_buf[64];
|
||||||
|
uint8_t *line_buf[2] = {NULL,NULL};
|
||||||
|
uint8_t lb_idx = 0;
|
||||||
|
uint8_t *scale_buf = NULL;
|
||||||
|
uint8_t scale_pix;
|
||||||
|
uint16_t co[3] = {0,0,0}; // RGB sum
|
||||||
|
uint8_t npix;
|
||||||
|
|
||||||
|
if (scale > 7) scale = 7;
|
||||||
|
scale_pix = scale+1; // scale factor ( 1~8 )
|
||||||
|
|
||||||
|
if (fname) {
|
||||||
|
// * File name is given, reading image from file
|
||||||
|
if (stat(fname, &sb) != 0) {
|
||||||
|
sprintf(err_buf, "opening file");
|
||||||
|
err = -1;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
size = sb.st_size;
|
||||||
|
fhndl = fopen(fname, "r");
|
||||||
|
if (!fhndl) {
|
||||||
|
sprintf(err_buf, "opening file");
|
||||||
|
err = -2;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
i = fread(buf, 1, 54, fhndl); // read header
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// * Reading image from buffer
|
||||||
|
if ((imgbuf) && (size > 54)) {
|
||||||
|
memcpy(buf, imgbuf, 54);
|
||||||
|
i = 54;
|
||||||
|
}
|
||||||
|
else i = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
sprintf(err_buf, "reading header");
|
||||||
|
if (i != 54) {err = -3; goto exit;}
|
||||||
|
|
||||||
|
// ** Check image header and get image properties
|
||||||
|
if ((buf[0] != 'B') || (buf[1] != 'M')) {err=-4; goto exit;} // accept only images with 'BM' id
|
||||||
|
|
||||||
|
memcpy(&temp, buf+2, 4); // file size
|
||||||
|
if (temp != size) {err=-5; goto exit;}
|
||||||
|
|
||||||
|
memcpy(&img_pos, buf+10, 4); // start of pixel data
|
||||||
|
|
||||||
|
memcpy(&temp, buf+14, 4); // BMP header size
|
||||||
|
if (temp != 40) {err=-6; goto exit;}
|
||||||
|
|
||||||
|
memcpy(&wtemp, buf+26, 2); // the number of color planes
|
||||||
|
if (wtemp != 1) {err=-7; goto exit;}
|
||||||
|
|
||||||
|
memcpy(&wtemp, buf+28, 2); // the number of bits per pixel
|
||||||
|
if (wtemp != 24) {err=-8; goto exit;}
|
||||||
|
|
||||||
|
memcpy(&temp, buf+30, 4); // the compression method being used
|
||||||
|
if (temp != 0) {err=-9; goto exit;}
|
||||||
|
|
||||||
|
memcpy(&img_xsize, buf+18, 4); // the bitmap width in pixels
|
||||||
|
memcpy(&img_ysize, buf+22, 4); // the bitmap height in pixels
|
||||||
|
|
||||||
|
|
||||||
|
// * scale image dimensions
|
||||||
|
/*
|
||||||
|
img_xlen = img_xsize / scale_pix; // image display horizontal size
|
||||||
|
img_ylen = img_ysize / scale_pix; // image display vertical size
|
||||||
|
|
||||||
|
if (x == CENTER) x = ((dispWin.x2 - dispWin.x1 + 1 - img_xlen) / 2) + dispWin.x1;
|
||||||
|
else if (x == RIGHT) x = dispWin.x2 + 1 - img_xlen;
|
||||||
|
|
||||||
|
if (y == CENTER) y = ((dispWin.y2 - dispWin.y1 + 1 - img_ylen) / 2) + dispWin.y1;
|
||||||
|
else if (y == BOTTOM) y = dispWin.y2 + 1 - img_ylen;
|
||||||
|
*/
|
||||||
|
if ((x < ((dispWin.x2 + 1) * -1)) || (x > (dispWin.x2 + 1)) || (y < ((dispWin.y2 + 1) * -1)) || (y > (dispWin.y2 + 1))) {
|
||||||
|
sprintf(err_buf, "out of display area (%d,%d", x, y);
|
||||||
|
err = -10;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ** set display and image areas
|
||||||
|
if (x < dispWin.x1) {
|
||||||
|
disp_xstart = dispWin.x1;
|
||||||
|
img_xstart = -x; // image pixel line X offset
|
||||||
|
img_xlen += x;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
disp_xstart = x;
|
||||||
|
img_xstart = 0;
|
||||||
|
}
|
||||||
|
if (y < dispWin.y1) {
|
||||||
|
disp_ystart = dispWin.y1;
|
||||||
|
img_ystart = -y; // image pixel line Y offset
|
||||||
|
img_ylen += y;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
disp_ystart = y;
|
||||||
|
img_ystart = 0;
|
||||||
|
}
|
||||||
|
disp_xend = disp_xstart + img_xlen - 1;
|
||||||
|
disp_yend = disp_ystart + img_ylen - 1;
|
||||||
|
if (disp_xend > dispWin.x2) {
|
||||||
|
disp_xend = dispWin.x2;
|
||||||
|
img_xlen = disp_xend - disp_xstart + 1;
|
||||||
|
}
|
||||||
|
if (disp_yend > dispWin.y2) {
|
||||||
|
disp_yend = dispWin.y2;
|
||||||
|
img_ylen = disp_yend - disp_ystart + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((img_xlen < 8) || (img_ylen < 8) || (img_xstart >= (img_xsize-2)) || ((img_ysize - img_ystart) < 2)) {
|
||||||
|
sprintf(err_buf, "image too small");
|
||||||
|
err = -11;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ** Allocate memory for 2 lines of image pixels
|
||||||
|
line_buf[0] = static_cast<uint8_t *>(heap_caps_malloc(img_xsize*3, MALLOC_CAP_DMA));
|
||||||
|
if (line_buf[0] == NULL) {
|
||||||
|
sprintf(err_buf, "allocating line buffer #1");
|
||||||
|
err=-12;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
line_buf[1] = static_cast<uint8_t *>(heap_caps_malloc(img_xsize*3, MALLOC_CAP_DMA));
|
||||||
|
if (line_buf[1] == NULL) {
|
||||||
|
sprintf(err_buf, "allocating line buffer #2");
|
||||||
|
err=-13;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (scale) {
|
||||||
|
// Allocate memory for scale buffer
|
||||||
|
rd_len = img_xlen * 3 * scale_pix;
|
||||||
|
scale_buf = static_cast<uint8_t *>(malloc(rd_len*scale_pix));
|
||||||
|
if (scale_buf == NULL) {
|
||||||
|
sprintf(err_buf, "allocating scale buffer");
|
||||||
|
err=-14;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else rd_len = img_xlen * 3;
|
||||||
|
|
||||||
|
// ** ***************************************************** **
|
||||||
|
// ** BMP images are stored in file from LAST to FIRST line **
|
||||||
|
// ** ***************************************************** **
|
||||||
|
|
||||||
|
/* Used variables:
|
||||||
|
img_xsize horizontal image size in pixels
|
||||||
|
img_ysize number of image lines
|
||||||
|
img_xlen image display horizontal scaled size in pixels
|
||||||
|
img_ylen image display vertical scaled size in pixels
|
||||||
|
img_xstart first pixel in line to be displayed
|
||||||
|
img_ystart first image line to be displayed
|
||||||
|
img_xlen number of pixels in image line to be displayed, starting with 'img_xstart'
|
||||||
|
img_ylen number of lines in image to be displayed, starting with 'img_ystart'
|
||||||
|
rd_len length of color data which are read from image line in bytes
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Set position in image to the first color data (beginning of the LAST line)
|
||||||
|
img_pos += (img_ystart * (img_xsize*3));
|
||||||
|
if (fhndl) {
|
||||||
|
if (fseek(fhndl, img_pos, SEEK_SET) != 0) {
|
||||||
|
sprintf(err_buf, "file seek at %d", img_pos);
|
||||||
|
err = -15;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (image_debug) printf("BMP: image size: (%d,%d) scale: %d disp size: (%d,%d) img xofs: %d img yofs: %d at: %d,%d; line buf: 2* %d scale buf: %d\r\n",
|
||||||
|
img_xsize, img_ysize, scale_pix, img_xlen, img_ylen, img_xstart, img_ystart, disp_xstart, disp_ystart, img_xsize*3, ((scale) ? (rd_len*scale_pix) : 0));
|
||||||
|
|
||||||
|
// * Select the display
|
||||||
|
//disp_select();
|
||||||
|
|
||||||
|
while ((disp_yend >= disp_ystart) && ((img_pos + (img_xsize*3)) <= size)) {
|
||||||
|
if (img_pos > size) {
|
||||||
|
sprintf(err_buf, "EOF reached: %d > %d", img_pos, size);
|
||||||
|
err = -16;
|
||||||
|
goto exit1;
|
||||||
|
}
|
||||||
|
if (scale == 0) {
|
||||||
|
// Read the line of color data into color buffer
|
||||||
|
if (fhndl) {
|
||||||
|
i = fread(line_buf[lb_idx], 1, img_xsize*3, fhndl); // read line from file
|
||||||
|
if (i != (img_xsize*3)) {
|
||||||
|
sprintf(err_buf, "file read at %d (%d<>%d)", img_pos, i, img_xsize*3);
|
||||||
|
err = -16;
|
||||||
|
goto exit1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else memcpy(line_buf[lb_idx], imgbuf+img_pos, img_xsize*3);
|
||||||
|
|
||||||
|
if (img_xstart > 0) memmove(line_buf[lb_idx], line_buf[lb_idx]+(img_xstart*3), rd_len);
|
||||||
|
// Convert colors BGR-888 (BMP) -> RGB-888 (DISPLAY) ===
|
||||||
|
for (i=0; i < rd_len; i += 3) {
|
||||||
|
tmpc = line_buf[lb_idx][i+2] & 0xfc; // save R
|
||||||
|
line_buf[lb_idx][i+2] = line_buf[lb_idx][i] & 0xfc; // B -> R
|
||||||
|
line_buf[lb_idx][i] = tmpc; // R -> B
|
||||||
|
line_buf[lb_idx][i+1] &= 0xfc; // G
|
||||||
|
}
|
||||||
|
img_pos += (img_xsize*3);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// scale image, read 'scale_pix' lines and find the average color
|
||||||
|
for (scan_lines=0; scan_lines<scale_pix; scan_lines++) {
|
||||||
|
if (img_pos > size) break;
|
||||||
|
if (fhndl) {
|
||||||
|
i = fread(line_buf[lb_idx], 1, img_xsize*3, fhndl); // read line from file
|
||||||
|
if (i != (img_xsize*3)) {
|
||||||
|
sprintf(err_buf, "file read at %d (%d<>%d)", img_pos, i, img_xsize*3);
|
||||||
|
err = -17;
|
||||||
|
goto exit1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else memcpy(line_buf[lb_idx], imgbuf+img_pos, img_xsize*3);
|
||||||
|
img_pos += (img_xsize*3);
|
||||||
|
|
||||||
|
// copy only data which are displayed to scale buffer
|
||||||
|
memcpy(scale_buf + (rd_len * scan_lines), line_buf[lb_idx]+img_xstart, rd_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Populate display line buffer
|
||||||
|
for (int n=0;n<(img_xlen*3);n += 3) {
|
||||||
|
memset(co, 0, sizeof(co)); // initialize color sum
|
||||||
|
npix = 0; // initialize number of pixels in scale rectangle
|
||||||
|
|
||||||
|
// sum all pixels in scale rectangle
|
||||||
|
for (int sc_line=0; sc_line<scan_lines; sc_line++) {
|
||||||
|
// Get colors position in scale buffer
|
||||||
|
img_pix_pos = (rd_len * sc_line) + (n * scale_pix);
|
||||||
|
|
||||||
|
for (int sc_col=0; sc_col<scale_pix; sc_col++) {
|
||||||
|
co[0] += scale_buf[img_pix_pos];
|
||||||
|
co[1] += scale_buf[img_pix_pos + 1];
|
||||||
|
co[2] += scale_buf[img_pix_pos + 2];
|
||||||
|
npix++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Place the average in display buffer, convert BGR-888 (BMP) -> RGB-888 (DISPLAY)
|
||||||
|
line_buf[lb_idx][n+2] = (uint8_t)(co[0] / npix); // B
|
||||||
|
line_buf[lb_idx][n+1] = (uint8_t)(co[1] / npix); // G
|
||||||
|
line_buf[lb_idx][n] = (uint8_t)(co[2] / npix); // R
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//wait_trans_finish(1);
|
||||||
|
//send_data(disp_xstart, disp_yend, disp_xend, disp_yend, img_xlen, (color_t *)line_buf[lb_idx]);
|
||||||
|
lb_idx = (lb_idx + 1) & 1; // change buffer
|
||||||
|
|
||||||
|
disp_yend--;
|
||||||
|
}
|
||||||
|
err = 0;
|
||||||
|
exit1:
|
||||||
|
//disp_deselect();
|
||||||
|
exit:
|
||||||
|
if (scale_buf) free(scale_buf);
|
||||||
|
if (line_buf[0]) free(line_buf[0]);
|
||||||
|
if (line_buf[1]) free(line_buf[1]);
|
||||||
|
if (fhndl) fclose(fhndl);
|
||||||
|
if ((err) && (image_debug)) printf("Error: %d [%s]\r\n", err, err_buf);
|
||||||
|
|
||||||
|
//return err;
|
||||||
|
}
|
Loading…
Reference in New Issue