[core] Refactor realtek-ambz, cleanup, reformat, add missing copyrights
This commit is contained in:
29
.clang-format
Normal file
29
.clang-format
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
Language: Cpp
|
||||||
|
BasedOnStyle: LLVM
|
||||||
|
AlignAfterOpenBracket: BlockIndent
|
||||||
|
AlignArrayOfStructures: Left
|
||||||
|
AlignConsecutiveAssignments: true
|
||||||
|
AlignConsecutiveMacros: AcrossComments
|
||||||
|
AlignTrailingComments: true
|
||||||
|
AllowAllArgumentsOnNextLine: false
|
||||||
|
AllowShortBlocksOnASingleLine: Empty
|
||||||
|
AllowShortFunctionsOnASingleLine: Empty
|
||||||
|
AlwaysBreakTemplateDeclarations: Yes
|
||||||
|
BinPackArguments: false
|
||||||
|
BinPackParameters: false
|
||||||
|
BreakBeforeTernaryOperators: true
|
||||||
|
ColumnLimit: 120
|
||||||
|
ContinuationIndentWidth: 4
|
||||||
|
EmptyLineBeforeAccessModifier: Always
|
||||||
|
FixNamespaceComments: true
|
||||||
|
IndentAccessModifiers: false
|
||||||
|
IndentCaseLabels: true
|
||||||
|
IndentWidth: 4
|
||||||
|
LambdaBodyIndentation: Signature
|
||||||
|
MaxEmptyLinesToKeep: 1
|
||||||
|
# PointerAlignment: Left # TODO enable this and reformat project
|
||||||
|
QualifierAlignment: Left
|
||||||
|
ReflowComments: true
|
||||||
|
SeparateDefinitionBlocks: Always
|
||||||
|
TabWidth: 4
|
||||||
|
UseTab: Always
|
||||||
1
.github/workflows/lint.yml
vendored
1
.github/workflows/lint.yml
vendored
@@ -6,7 +6,6 @@ jobs:
|
|||||||
lint-clang-format:
|
lint-clang-format:
|
||||||
name: Lint with clang-format
|
name: Lint with clang-format
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
if: ${{ false }} # disable for now
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
/* Copyright (c) Kuba Szczodrzyński 2022-04-24. */
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
/* Copyright (c) Kuba Szczodrzyński 2022-04-29. */
|
||||||
|
|
||||||
#include "LibreTuyaAPI.h"
|
#include "LibreTuyaAPI.h"
|
||||||
|
|
||||||
__weak char *strdup(const char *s) {
|
__weak char *strdup(const char *s) {
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
/* Copyright (c) Kuba Szczodrzyński 2022-04-28. */
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
// LibreTuya version macros
|
// LibreTuya version macros
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
/* Copyright (c) Kuba Szczodrzyński 2022-04-28. */
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
// see docs/API Configuration
|
// see docs/API Configuration
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
/* Copyright (c) Kuba Szczodrzyński 2022-04-28. */
|
||||||
|
|
||||||
#include "lt_logger.h"
|
#include "lt_logger.h"
|
||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
/* Copyright (c) Kuba Szczodrzyński 2022-04-28. */
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "LibreTuyaConfig.h"
|
#include "LibreTuyaConfig.h"
|
||||||
|
|||||||
55
arduino/libretuya/common/WMath.cpp
Normal file
55
arduino/libretuya/common/WMath.cpp
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2014 Arduino. All right reserved.
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
void randomSeed(uint32_t dwSeed) {
|
||||||
|
if (dwSeed != 0) {
|
||||||
|
srand(dwSeed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
long random(long howbig) {
|
||||||
|
if (howbig == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rand() % howbig;
|
||||||
|
}
|
||||||
|
|
||||||
|
long random(long howsmall, long howbig) {
|
||||||
|
if (howsmall >= howbig) {
|
||||||
|
return howsmall;
|
||||||
|
}
|
||||||
|
|
||||||
|
long diff = howbig - howsmall;
|
||||||
|
|
||||||
|
return random(diff) + howsmall;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern long map(long x, long in_min, long in_max, long out_min, long out_max) {
|
||||||
|
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern uint16_t makeWord(uint16_t w) {
|
||||||
|
return w;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern uint16_t makeWord(uint8_t h, uint8_t l) {
|
||||||
|
return (h << 8) | l;
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
Copyright (c) 2012 Arduino. All right reserved.
|
Copyright (c) 2014 Arduino LLC. All right reserved.
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
This library is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
@@ -16,19 +16,21 @@
|
|||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef RESET_H
|
#include <stdlib.h>
|
||||||
#define RESET_H
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
extern "C" void __cxa_pure_virtual(void) __attribute__((__noreturn__));
|
||||||
extern "C" {
|
extern "C" void __cxa_deleted_virtual(void) __attribute__((__noreturn__));
|
||||||
#endif
|
|
||||||
|
|
||||||
void initiateReset(int ms);
|
void __cxa_pure_virtual(void) {
|
||||||
void tickReset();
|
// We might want to write some diagnostics to uart in this case
|
||||||
void cancelReset();
|
// std::terminate();
|
||||||
|
while (1)
|
||||||
#ifdef __cplusplus
|
;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
void __cxa_deleted_virtual(void) {
|
||||||
|
// We might want to write some diagnostics to uart in this case
|
||||||
|
// std::terminate();
|
||||||
|
while (1)
|
||||||
|
;
|
||||||
|
}
|
||||||
@@ -18,16 +18,11 @@
|
|||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef ARDUINO_AMEBA
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#else
|
|
||||||
#include <stdio.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
char *dtostrf (double val, signed char width, unsigned char prec, char *sout) {
|
char *dtostrf(double val, signed char width, unsigned char prec, char *sout) {
|
||||||
char fmt[20];
|
char fmt[20];
|
||||||
sprintf(fmt, "%%%d.%df", width, prec);
|
sprintf(fmt, "%%%d.%df", width, prec);
|
||||||
sprintf(sout, fmt, val);
|
sprintf(sout, fmt, val);
|
||||||
return sout;
|
return sout;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
Copyright (c) 2012 Arduino. All right reserved.
|
Copyright (c) 2015 Arduino LLC. All right reserved.
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
This library is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
@@ -29,12 +29,7 @@ static void __empty() {
|
|||||||
// Empty
|
// Empty
|
||||||
}
|
}
|
||||||
|
|
||||||
#include "cmsis_os.h"
|
void yield(void) __attribute__((weak, alias("__empty")));
|
||||||
|
|
||||||
void yield(void) {
|
|
||||||
vTaskDelay(1);
|
|
||||||
taskYIELD();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SysTick hook
|
* SysTick hook
|
||||||
@@ -46,7 +41,8 @@ static int __false() {
|
|||||||
// Return false
|
// Return false
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
int sysTickHook(void) __attribute__ ((weak, alias("__false")));
|
|
||||||
|
int sysTickHook(void) __attribute__((weak, alias("__false")));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SVC hook
|
* SVC hook
|
||||||
@@ -60,5 +56,6 @@ static void __halt() {
|
|||||||
while (1)
|
while (1)
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
void svcHook(void) __attribute__ ((weak, alias("__halt")));
|
|
||||||
void pendSVHook(void) __attribute__ ((weak, alias("__halt")));
|
void svcHook(void) __attribute__((weak, alias("__halt")));
|
||||||
|
void pendSVHook(void) __attribute__((weak, alias("__halt")));
|
||||||
111
arduino/libretuya/common/itoa.c
Normal file
111
arduino/libretuya/common/itoa.c
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2014 Arduino LLC. All right reserved.
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
char *ltoa(long value, char *string, int radix) {
|
||||||
|
char tmp[33];
|
||||||
|
char *tp = tmp;
|
||||||
|
long i;
|
||||||
|
unsigned long v;
|
||||||
|
int sign;
|
||||||
|
char *sp;
|
||||||
|
|
||||||
|
if (string == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (radix > 36 || radix <= 1) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
sign = (radix == 10 && value < 0);
|
||||||
|
if (sign) {
|
||||||
|
v = -value;
|
||||||
|
} else {
|
||||||
|
v = (unsigned long)value;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (v || tp == tmp) {
|
||||||
|
i = v % radix;
|
||||||
|
v = v / radix;
|
||||||
|
if (i < 10)
|
||||||
|
*tp++ = i + '0';
|
||||||
|
else
|
||||||
|
*tp++ = i + 'a' - 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
sp = string;
|
||||||
|
|
||||||
|
if (sign)
|
||||||
|
*sp++ = '-';
|
||||||
|
while (tp > tmp)
|
||||||
|
*sp++ = *--tp;
|
||||||
|
*sp = 0;
|
||||||
|
|
||||||
|
return string;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *ultoa(unsigned long value, char *string, int radix) {
|
||||||
|
char tmp[33];
|
||||||
|
char *tp = tmp;
|
||||||
|
long i;
|
||||||
|
unsigned long v = value;
|
||||||
|
char *sp;
|
||||||
|
|
||||||
|
if (string == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (radix > 36 || radix <= 1) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (v || tp == tmp) {
|
||||||
|
i = v % radix;
|
||||||
|
v = v / radix;
|
||||||
|
if (i < 10)
|
||||||
|
*tp++ = i + '0';
|
||||||
|
else
|
||||||
|
*tp++ = i + 'a' - 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
sp = string;
|
||||||
|
|
||||||
|
while (tp > tmp)
|
||||||
|
*sp++ = *--tp;
|
||||||
|
*sp = 0;
|
||||||
|
|
||||||
|
return string;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *itoa(int value, char *string, int radix) {
|
||||||
|
return ltoa(value, string, radix);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *utoa(unsigned int value, char *string, int radix) {
|
||||||
|
return ultoa(value, string, radix);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} // extern "C"
|
||||||
|
#endif
|
||||||
54
arduino/libretuya/common/wiring_shift.c
Normal file
54
arduino/libretuya/common/wiring_shift.c
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2014 Arduino. All right reserved.
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
uint8_t shiftIn(pin_size_t ulDataPin, pin_size_t ulClockPin, BitOrder ulBitOrder) {
|
||||||
|
uint8_t value = 0;
|
||||||
|
uint8_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < 8; ++i) {
|
||||||
|
digitalWrite(ulClockPin, HIGH);
|
||||||
|
|
||||||
|
if (ulBitOrder == LSBFIRST) {
|
||||||
|
value |= digitalRead(ulDataPin) << i;
|
||||||
|
} else {
|
||||||
|
value |= digitalRead(ulDataPin) << (7 - i);
|
||||||
|
}
|
||||||
|
|
||||||
|
digitalWrite(ulClockPin, LOW);
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void shiftOut(pin_size_t ulDataPin, pin_size_t ulClockPin, BitOrder ulBitOrder, uint8_t ulVal) {
|
||||||
|
uint8_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < 8; i++) {
|
||||||
|
if (ulBitOrder == LSBFIRST) {
|
||||||
|
digitalWrite(ulDataPin, !!(ulVal & (1 << i)));
|
||||||
|
} else {
|
||||||
|
digitalWrite(ulDataPin, !!(ulVal & (1 << (7 - i))));
|
||||||
|
}
|
||||||
|
|
||||||
|
digitalWrite(ulClockPin, HIGH);
|
||||||
|
digitalWrite(ulClockPin, LOW);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
/* Copyright (c) Kuba Szczodrzyński 2022-04-30. */
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <api/FS.h>
|
#include <api/FS.h>
|
||||||
|
|||||||
@@ -1 +1,3 @@
|
|||||||
|
/* Copyright (c) Kuba Szczodrzyński 2022-04-30. */
|
||||||
|
|
||||||
// nop
|
// nop
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
/* Copyright (c) Kuba Szczodrzyński 2022-04-26. */
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
// ESP32 WiFi examples use WiFiAP.h include
|
// ESP32 WiFi examples use WiFiAP.h include
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
/* Copyright (c) Kuba Szczodrzyński 2022-04-30. */
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <api/deprecated-avr-comp/avr/pgmspace.h>
|
#include <api/deprecated-avr-comp/avr/pgmspace.h>
|
||||||
|
|||||||
@@ -1 +1,3 @@
|
|||||||
|
/* Copyright (c) Kuba Szczodrzyński 2022-04-30. */
|
||||||
|
|
||||||
// nop
|
// nop
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
/* Copyright (c) Kuba Szczodrzyński 2022-04-29. */
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
DisableFormat: true
|
||||||
|
SortIncludes: Never
|
||||||
@@ -17,75 +17,82 @@
|
|||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "IPv6Address.h"
|
||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <api/Print.h>
|
#include <api/Print.h>
|
||||||
|
|
||||||
#include "IPv6Address.h"
|
IPv6Address::IPv6Address() {
|
||||||
|
memset(_address.bytes, 0, sizeof(_address.bytes));
|
||||||
IPv6Address::IPv6Address()
|
|
||||||
{
|
|
||||||
memset(_address.bytes, 0, sizeof(_address.bytes));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
IPv6Address::IPv6Address(const uint8_t *address)
|
IPv6Address::IPv6Address(const uint8_t *address) {
|
||||||
{
|
memcpy(_address.bytes, address, sizeof(_address.bytes));
|
||||||
memcpy(_address.bytes, address, sizeof(_address.bytes));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
IPv6Address::IPv6Address(const uint32_t *address)
|
IPv6Address::IPv6Address(const uint32_t *address) {
|
||||||
{
|
memcpy(_address.bytes, (const uint8_t *)address, sizeof(_address.bytes));
|
||||||
memcpy(_address.bytes, (const uint8_t *)address, sizeof(_address.bytes));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
IPv6Address& IPv6Address::operator=(const uint8_t *address)
|
IPv6Address &IPv6Address::operator=(const uint8_t *address) {
|
||||||
{
|
memcpy(_address.bytes, address, sizeof(_address.bytes));
|
||||||
memcpy(_address.bytes, address, sizeof(_address.bytes));
|
return *this;
|
||||||
return *this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IPv6Address::operator==(const uint8_t* addr) const
|
bool IPv6Address::operator==(const uint8_t *addr) const {
|
||||||
{
|
return memcmp(addr, _address.bytes, sizeof(_address.bytes)) == 0;
|
||||||
return memcmp(addr, _address.bytes, sizeof(_address.bytes)) == 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t IPv6Address::printTo(Print& p) const
|
size_t IPv6Address::printTo(Print &p) const {
|
||||||
{
|
/* size_t n = 0;
|
||||||
/* size_t n = 0;
|
for(int i = 0; i < 16; i+=2) {
|
||||||
for(int i = 0; i < 16; i+=2) {
|
if(i){
|
||||||
if(i){
|
n += p.print(':');
|
||||||
n += p.print(':');
|
}
|
||||||
}
|
n += p.printf("%02x", _address.bytes[i]);
|
||||||
n += p.printf("%02x", _address.bytes[i]);
|
n += p.printf("%02x", _address.bytes[i+1]);
|
||||||
n += p.printf("%02x", _address.bytes[i+1]);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
return n; */
|
return n; */
|
||||||
}
|
}
|
||||||
|
|
||||||
String IPv6Address::toString() const
|
String IPv6Address::toString() const {
|
||||||
{
|
char szRet[40];
|
||||||
char szRet[40];
|
sprintf(
|
||||||
sprintf(szRet,"%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x",
|
szRet,
|
||||||
_address.bytes[0], _address.bytes[1], _address.bytes[2], _address.bytes[3],
|
"%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x",
|
||||||
_address.bytes[4], _address.bytes[5], _address.bytes[6], _address.bytes[7],
|
_address.bytes[0],
|
||||||
_address.bytes[8], _address.bytes[9], _address.bytes[10], _address.bytes[11],
|
_address.bytes[1],
|
||||||
_address.bytes[12], _address.bytes[13], _address.bytes[14], _address.bytes[15]);
|
_address.bytes[2],
|
||||||
return String(szRet);
|
_address.bytes[3],
|
||||||
|
_address.bytes[4],
|
||||||
|
_address.bytes[5],
|
||||||
|
_address.bytes[6],
|
||||||
|
_address.bytes[7],
|
||||||
|
_address.bytes[8],
|
||||||
|
_address.bytes[9],
|
||||||
|
_address.bytes[10],
|
||||||
|
_address.bytes[11],
|
||||||
|
_address.bytes[12],
|
||||||
|
_address.bytes[13],
|
||||||
|
_address.bytes[14],
|
||||||
|
_address.bytes[15]
|
||||||
|
);
|
||||||
|
return String(szRet);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IPv6Address::fromString(const char *address)
|
bool IPv6Address::fromString(const char *address) {
|
||||||
{
|
// format 0011:2233:4455:6677:8899:aabb:ccdd:eeff
|
||||||
//format 0011:2233:4455:6677:8899:aabb:ccdd:eeff
|
if (strlen(address) != 39) {
|
||||||
if(strlen(address) != 39){
|
return false;
|
||||||
return false;
|
}
|
||||||
}
|
char *pos = (char *)address;
|
||||||
char * pos = (char *)address;
|
size_t i = 0;
|
||||||
size_t i = 0;
|
for (i = 0; i < 16; i += 2) {
|
||||||
for(i = 0; i < 16; i+=2) {
|
if (!sscanf(pos, "%2hhx", &_address.bytes[i]) || !sscanf(pos + 2, "%2hhx", &_address.bytes[i + 1])) {
|
||||||
if(!sscanf(pos, "%2hhx", &_address.bytes[i]) || !sscanf(pos+2, "%2hhx", &_address.bytes[i+1])){
|
return false;
|
||||||
return false;
|
}
|
||||||
}
|
pos += 5;
|
||||||
pos += 5;
|
}
|
||||||
}
|
return true;
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,80 +19,79 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <api/String.h>
|
|
||||||
#include <api/Print.h>
|
#include <api/Print.h>
|
||||||
|
#include <api/String.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
// A class to make it easier to handle and pass around IP addresses
|
// A class to make it easier to handle and pass around IP addresses
|
||||||
|
|
||||||
namespace arduino {
|
namespace arduino {
|
||||||
|
|
||||||
class IPv6Address: public Printable
|
class IPv6Address : public Printable {
|
||||||
{
|
private:
|
||||||
private:
|
union {
|
||||||
union {
|
uint8_t bytes[16]; // IPv4 address
|
||||||
uint8_t bytes[16]; // IPv4 address
|
uint32_t dword[4];
|
||||||
uint32_t dword[4];
|
} _address;
|
||||||
} _address;
|
|
||||||
|
|
||||||
// Access the raw byte array containing the address. Because this returns a pointer
|
// Access the raw byte array containing the address. Because this returns a pointer
|
||||||
// to the internal structure rather than a copy of the address this function should only
|
// to the internal structure rather than a copy of the address this function should only
|
||||||
// be used when you know that the usage of the returned uint8_t* will be transient and not
|
// be used when you know that the usage of the returned uint8_t* will be transient and not
|
||||||
// stored.
|
// stored.
|
||||||
uint8_t* raw_address()
|
uint8_t *raw_address() {
|
||||||
{
|
return _address.bytes;
|
||||||
return _address.bytes;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Constructors
|
// Constructors
|
||||||
IPv6Address();
|
IPv6Address();
|
||||||
IPv6Address(const uint8_t *address);
|
IPv6Address(const uint8_t *address);
|
||||||
IPv6Address(const uint32_t *address);
|
IPv6Address(const uint32_t *address);
|
||||||
virtual ~IPv6Address() {}
|
|
||||||
|
|
||||||
bool fromString(const char *address);
|
virtual ~IPv6Address() {}
|
||||||
bool fromString(const String &address) { return fromString(address.c_str()); }
|
|
||||||
|
|
||||||
operator const uint8_t*() const
|
bool fromString(const char *address);
|
||||||
{
|
|
||||||
return _address.bytes;
|
|
||||||
}
|
|
||||||
operator const uint32_t*() const
|
|
||||||
{
|
|
||||||
return _address.dword;
|
|
||||||
}
|
|
||||||
bool operator==(const IPv6Address& addr) const
|
|
||||||
{
|
|
||||||
return (_address.dword[0] == addr._address.dword[0])
|
|
||||||
&& (_address.dword[1] == addr._address.dword[1])
|
|
||||||
&& (_address.dword[2] == addr._address.dword[2])
|
|
||||||
&& (_address.dword[3] == addr._address.dword[3]);
|
|
||||||
}
|
|
||||||
bool operator==(const uint8_t* addr) const;
|
|
||||||
|
|
||||||
// Overloaded index operator to allow getting and setting individual octets of the address
|
bool fromString(const String &address) {
|
||||||
uint8_t operator[](int index) const
|
return fromString(address.c_str());
|
||||||
{
|
}
|
||||||
return _address.bytes[index];
|
|
||||||
}
|
|
||||||
uint8_t& operator[](int index)
|
|
||||||
{
|
|
||||||
return _address.bytes[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Overloaded copy operators to allow initialisation of IPv6Address objects from other types
|
operator const uint8_t *() const {
|
||||||
IPv6Address& operator=(const uint8_t *address);
|
return _address.bytes;
|
||||||
|
}
|
||||||
|
|
||||||
// TODO implement printTo()
|
operator const uint32_t *() const {
|
||||||
virtual size_t printTo(Print& p) const;
|
return _address.dword;
|
||||||
String toString() const;
|
}
|
||||||
|
|
||||||
friend class UDP;
|
bool operator==(const IPv6Address &addr) const {
|
||||||
friend class Client;
|
return (_address.dword[0] == addr._address.dword[0]) && (_address.dword[1] == addr._address.dword[1]) &&
|
||||||
friend class Server;
|
(_address.dword[2] == addr._address.dword[2]) && (_address.dword[3] == addr._address.dword[3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const uint8_t *addr) const;
|
||||||
|
|
||||||
|
// Overloaded index operator to allow getting and setting individual octets of the address
|
||||||
|
uint8_t operator[](int index) const {
|
||||||
|
return _address.bytes[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t &operator[](int index) {
|
||||||
|
return _address.bytes[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Overloaded copy operators to allow initialisation of IPv6Address objects from other types
|
||||||
|
IPv6Address &operator=(const uint8_t *address);
|
||||||
|
|
||||||
|
// TODO implement printTo()
|
||||||
|
virtual size_t printTo(Print &p) const;
|
||||||
|
String toString() const;
|
||||||
|
|
||||||
|
friend class UDP;
|
||||||
|
friend class Client;
|
||||||
|
friend class Server;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
} // namespace arduino
|
||||||
|
|
||||||
using arduino::IPv6Address;
|
using arduino::IPv6Address;
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ size_t LwIPRxBuffer::r_available() {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
uint16_t count = 0;
|
uint16_t count = 0;
|
||||||
int res = lwip_ioctl(_sock, FIONREAD, &count);
|
int res = lwip_ioctl(_sock, FIONREAD, &count);
|
||||||
if (res < 0) {
|
if (res < 0) {
|
||||||
_failed = true;
|
_failed = true;
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
/* Copyright (c) Kuba Szczodrzyński 2022-04-30. */
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "../IPv6Address.h"
|
#include "../IPv6Address.h"
|
||||||
|
|||||||
2
arduino/libretuya/libraries/base64/.clang-format
Normal file
2
arduino/libretuya/libraries/base64/.clang-format
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
DisableFormat: true
|
||||||
|
SortIncludes: Never
|
||||||
@@ -1,58 +1,29 @@
|
|||||||
/*
|
/* Copyright (c) Kuba Szczodrzyński 2022-04-23. */
|
||||||
Arduino.h - Main include file for the Arduino SDK
|
|
||||||
Copyright (c) 2005-2013 Arduino Team. All right reserved.
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
#include "WCharacterFixup.h"
|
#include "WCharacterFixup.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define PinMode PinModeArduino // this conflicts with SDK enum
|
#define PinMode PinModeArduino // this conflicts with SDK enum
|
||||||
#include <api/ArduinoAPI.h>
|
#include <api/ArduinoAPI.h>
|
||||||
#include <api/LibreTuyaAPI.h>
|
#include <api/LibreTuyaAPI.h>
|
||||||
#undef PinMode
|
#undef PinMode
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" uint32_t SystemCoreClock;
|
||||||
#endif // __cplusplus
|
#else
|
||||||
|
|
||||||
extern uint32_t SystemCoreClock;
|
extern uint32_t SystemCoreClock;
|
||||||
|
|
||||||
#define clockCyclesPerMicrosecond() ( SystemCoreClock / 1000000L )
|
|
||||||
#define clockCyclesToMicroseconds(a) ( ((a) * 1000L) / (SystemCoreClock / 1000L) )
|
|
||||||
#define microsecondsToClockCycles(a) ( (a) * (SystemCoreClock / 1000000L) )
|
|
||||||
|
|
||||||
#include "WVariant.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
} // extern "C"
|
|
||||||
#endif
|
#endif
|
||||||
|
#define clockCyclesPerMicrosecond() (SystemCoreClock / 1000000L)
|
||||||
|
#define clockCyclesToMicroseconds(a) (((a)*1000L) / (SystemCoreClock / 1000L))
|
||||||
|
#define microsecondsToClockCycles(a) ((a) * (SystemCoreClock / 1000000L))
|
||||||
|
|
||||||
// Include board variant
|
#define interrupts() vPortClearInterruptMask(0)
|
||||||
#include "variant.h"
|
|
||||||
|
|
||||||
#define interrupts() vPortClearInterruptMask(0)
|
|
||||||
#define noInterrupts() ulPortSetInterruptMask()
|
#define noInterrupts() ulPortSetInterruptMask()
|
||||||
|
|
||||||
/*
|
// Include platform-specific code
|
||||||
* \brief SAM3 products have only one reference for ADC
|
#include "WVariant.h"
|
||||||
*/
|
// Include board variant
|
||||||
typedef enum _eAnalogReference
|
#include "variant.h"
|
||||||
{
|
|
||||||
AR_DEFAULT,
|
|
||||||
} eAnalogReference ;
|
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
#include <api/Print.h>
|
|
||||||
|
|
||||||
class CountingStream : public Print
|
|
||||||
{
|
|
||||||
virtual size_t write(uint8_t) { return 1; };
|
|
||||||
virtual size_t write(const uint8_t *buffer, size_t size) { return size; };
|
|
||||||
};
|
|
||||||
@@ -1,198 +0,0 @@
|
|||||||
/* mbed Microcontroller Library
|
|
||||||
* Copyright (c) 2006-2015 ARM Limited
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
#ifndef MBED_FUNCTIONPOINTER_H
|
|
||||||
#define MBED_FUNCTIONPOINTER_H
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
|
|
||||||
/* If we had variaditic templates, this wouldn't be a problem, but until C++11 is enabled, we are stuck with multiple classes... */
|
|
||||||
|
|
||||||
/** A class for storing and calling a pointer to a static or member function
|
|
||||||
*/
|
|
||||||
template <typename R, typename A1>
|
|
||||||
class FunctionPointerArg1{
|
|
||||||
public:
|
|
||||||
/** Create a FunctionPointer, attaching a static function
|
|
||||||
*
|
|
||||||
* @param function The static function to attach (default is none)
|
|
||||||
*/
|
|
||||||
FunctionPointerArg1(R (*function)(A1) = 0) {
|
|
||||||
attach(function);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Create a FunctionPointer, attaching a member function
|
|
||||||
*
|
|
||||||
* @param object The object pointer to invoke the member function on (i.e. the this pointer)
|
|
||||||
* @param function The address of the member function to attach
|
|
||||||
*/
|
|
||||||
template<typename T>
|
|
||||||
FunctionPointerArg1(T *object, R (T::*member)(A1)) {
|
|
||||||
attach(object, member);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Attach a static function
|
|
||||||
*
|
|
||||||
* @param function The static function to attach (default is none)
|
|
||||||
*/
|
|
||||||
void attach(R (*function)(A1)) {
|
|
||||||
_p.function = function;
|
|
||||||
_membercaller = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Attach a member function
|
|
||||||
*
|
|
||||||
* @param object The object pointer to invoke the member function on (i.e. the this pointer)
|
|
||||||
* @param function The address of the member function to attach
|
|
||||||
*/
|
|
||||||
template<typename T>
|
|
||||||
void attach(T *object, R (T::*member)(A1)) {
|
|
||||||
_p.object = static_cast<void*>(object);
|
|
||||||
*reinterpret_cast<R (T::**)(A1)>(_member) = member;
|
|
||||||
_membercaller = &FunctionPointerArg1::membercaller<T>;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Call the attached static or member function
|
|
||||||
*/
|
|
||||||
R call(A1 a) {
|
|
||||||
if (_membercaller == 0 && _p.function) {
|
|
||||||
return _p.function(a);
|
|
||||||
} else if (_membercaller && _p.object) {
|
|
||||||
return _membercaller(_p.object, _member, a);
|
|
||||||
}
|
|
||||||
return (R)0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get registered static function
|
|
||||||
*/
|
|
||||||
R(*get_function(A1))() {
|
|
||||||
return _membercaller ? (R(*)(A1))0 : (R(*)(A1))_p.function;
|
|
||||||
}
|
|
||||||
|
|
||||||
R operator ()(A1 a) {
|
|
||||||
return call(a);
|
|
||||||
}
|
|
||||||
operator bool(void) const {
|
|
||||||
return (_membercaller != NULL ? _p.object : (void*)_p.function) != NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
template<typename T>
|
|
||||||
static R membercaller(void *object, uintptr_t *member, A1 a) {
|
|
||||||
T* o = static_cast<T*>(object);
|
|
||||||
R (T::**m)(A1) = reinterpret_cast<R (T::**)(A1)>(member);
|
|
||||||
return (o->**m)(a);
|
|
||||||
}
|
|
||||||
|
|
||||||
union {
|
|
||||||
R (*function)(A1); // static function pointer
|
|
||||||
void *object; // object this pointer
|
|
||||||
} _p;
|
|
||||||
uintptr_t _member[4]; // aligned raw member function pointer storage - converted back by registered _membercaller
|
|
||||||
R (*_membercaller)(void*, uintptr_t*, A1); // registered membercaller function to convert back and call _m.member on _object
|
|
||||||
};
|
|
||||||
|
|
||||||
/** A class for storing and calling a pointer to a static or member function (R ()(void))
|
|
||||||
*/
|
|
||||||
template <typename R>
|
|
||||||
class FunctionPointerArg1<R, void>{
|
|
||||||
public:
|
|
||||||
/** Create a FunctionPointer, attaching a static function
|
|
||||||
*
|
|
||||||
* @param function The static function to attach (default is none)
|
|
||||||
*/
|
|
||||||
FunctionPointerArg1(R (*function)(void) = 0) {
|
|
||||||
attach(function);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Create a FunctionPointer, attaching a member function
|
|
||||||
*
|
|
||||||
* @param object The object pointer to invoke the member function on (i.e. the this pointer)
|
|
||||||
* @param function The address of the void member function to attach
|
|
||||||
*/
|
|
||||||
template<typename T>
|
|
||||||
FunctionPointerArg1(T *object, R (T::*member)(void)) {
|
|
||||||
attach(object, member);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Attach a static function
|
|
||||||
*
|
|
||||||
* @param function The void static function to attach (default is none)
|
|
||||||
*/
|
|
||||||
void attach(R (*function)(void)) {
|
|
||||||
_p.function = function;
|
|
||||||
_membercaller = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Attach a member function
|
|
||||||
*
|
|
||||||
* @param object The object pointer to invoke the member function on (i.e. the this pointer)
|
|
||||||
* @param function The address of the void member function to attach
|
|
||||||
*/
|
|
||||||
template<typename T>
|
|
||||||
void attach(T *object, R (T::*member)(void)) {
|
|
||||||
_p.object = static_cast<void*>(object);
|
|
||||||
*reinterpret_cast<R (T::**)(void)>(_member) = member;
|
|
||||||
_membercaller = &FunctionPointerArg1::membercaller<T>;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Call the attached static or member function
|
|
||||||
*/
|
|
||||||
R call(){
|
|
||||||
if (_membercaller == 0 && _p.function) {
|
|
||||||
return _p.function();
|
|
||||||
} else if (_membercaller && _p.object) {
|
|
||||||
return _membercaller(_p.object, _member);
|
|
||||||
}
|
|
||||||
return (R)0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get registered static function
|
|
||||||
*/
|
|
||||||
R(*get_function())() {
|
|
||||||
return _membercaller ? (R(*)())0 : (R(*)())_p.function;
|
|
||||||
}
|
|
||||||
|
|
||||||
R operator ()(void) {
|
|
||||||
return call();
|
|
||||||
}
|
|
||||||
operator bool(void) const {
|
|
||||||
return (_membercaller != NULL ? _p.object : (void*)_p.function) != NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
template<typename T>
|
|
||||||
static R membercaller(void *object, uintptr_t *member) {
|
|
||||||
T* o = static_cast<T*>(object);
|
|
||||||
R (T::**m)(void) = reinterpret_cast<R (T::**)(void)>(member);
|
|
||||||
return (o->**m)();
|
|
||||||
}
|
|
||||||
|
|
||||||
union {
|
|
||||||
R (*function)(void); // static function pointer
|
|
||||||
void *object; // object this pointer
|
|
||||||
} _p;
|
|
||||||
uintptr_t _member[4]; // aligned raw member function pointer storage - converted back by registered _membercaller
|
|
||||||
R (*_membercaller)(void*, uintptr_t*); // registered membercaller function to convert back and call _m.member on _object
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef FunctionPointerArg1<void, void> FunctionPointer;
|
|
||||||
typedef FunctionPointerArg1<void, int> event_callback_t;
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
@@ -16,117 +16,83 @@
|
|||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "Arduino.h"
|
|
||||||
|
|
||||||
#include "LOGUARTClass.h"
|
#include "LOGUARTClass.h"
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
#define LOG_UART_MODIFIABLE_BAUD_RATE 1
|
#define LOG_UART_MODIFIABLE_BAUD_RATE 1
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "osdep_service.h"
|
|
||||||
#include "rtl8710b.h"
|
|
||||||
extern int LOGUART_SetBaud(uint32_t BaudRate); // from fixups/log_uart.c
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
RingBuffer rx_buffer0;
|
RingBuffer rx_buffer0;
|
||||||
|
|
||||||
LOGUARTClass::LOGUARTClass(int dwIrq, RingBuffer* pRx_buffer )
|
LOGUARTClass::LOGUARTClass(int dwIrq, RingBuffer *pRx_buffer) {
|
||||||
{
|
_rx_buffer = pRx_buffer;
|
||||||
_rx_buffer = pRx_buffer;
|
_dwIrq = dwIrq;
|
||||||
_dwIrq = dwIrq;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Protected Methods //////////////////////////////////////////////////////////////
|
void IrqHandler(void) {
|
||||||
|
uint8_t data = 0;
|
||||||
|
BOOL PullMode = _FALSE;
|
||||||
|
uint32_t IrqEn = DiagGetIsrEnReg();
|
||||||
|
|
||||||
|
DiagSetIsrEnReg(0);
|
||||||
|
|
||||||
|
data = DiagGetChar(PullMode);
|
||||||
|
if (data > 0)
|
||||||
// Public Methods //////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
|
|
||||||
void IrqHandler( void )
|
|
||||||
{
|
|
||||||
|
|
||||||
uint8_t data = 0;
|
|
||||||
BOOL PullMode = _FALSE;
|
|
||||||
uint32_t IrqEn = DiagGetIsrEnReg();
|
|
||||||
|
|
||||||
DiagSetIsrEnReg(0);
|
|
||||||
|
|
||||||
data = DiagGetChar(PullMode);
|
|
||||||
if ( data > 0 )
|
|
||||||
rx_buffer0.store_char(data);
|
rx_buffer0.store_char(data);
|
||||||
|
|
||||||
DiagSetIsrEnReg(IrqEn);
|
DiagSetIsrEnReg(IrqEn);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LOGUARTClass::begin(const uint32_t dwBaudRate) {
|
||||||
void LOGUARTClass::begin( const uint32_t dwBaudRate )
|
DIAG_UartReInit((IRQ_FUN)IrqHandler);
|
||||||
{
|
NVIC_SetPriority(UART_LOG_IRQ, 10);
|
||||||
DIAG_UartReInit((IRQ_FUN) IrqHandler);
|
LOGUART_SetBaud(dwBaudRate);
|
||||||
NVIC_SetPriority(UART_LOG_IRQ, 10);
|
|
||||||
LOGUART_SetBaud(dwBaudRate);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LOGUARTClass::end( void )
|
void LOGUARTClass::end(void) {
|
||||||
{
|
// clear any received data
|
||||||
// clear any received data
|
_rx_buffer->_iHead = _rx_buffer->_iTail;
|
||||||
_rx_buffer->_iHead = _rx_buffer->_iTail ;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int LOGUARTClass::available( void )
|
int LOGUARTClass::available(void) {
|
||||||
{
|
return (uint32_t)(SERIAL_BUFFER_SIZE + _rx_buffer->_iHead - _rx_buffer->_iTail) % SERIAL_BUFFER_SIZE;
|
||||||
return (uint32_t)(SERIAL_BUFFER_SIZE + _rx_buffer->_iHead - _rx_buffer->_iTail) % SERIAL_BUFFER_SIZE ;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int LOGUARTClass::peek( void )
|
int LOGUARTClass::peek(void) {
|
||||||
{
|
|
||||||
|
|
||||||
if ( _rx_buffer->_iHead == _rx_buffer->_iTail )
|
if (_rx_buffer->_iHead == _rx_buffer->_iTail)
|
||||||
return -1 ;
|
return -1;
|
||||||
|
|
||||||
return _rx_buffer->_aucBuffer[_rx_buffer->_iTail] ;
|
|
||||||
|
|
||||||
|
return _rx_buffer->_aucBuffer[_rx_buffer->_iTail];
|
||||||
}
|
}
|
||||||
|
|
||||||
int LOGUARTClass::read( void )
|
int LOGUARTClass::read(void) {
|
||||||
{
|
// if the head isn't ahead of the tail, we don't have any characters
|
||||||
// if the head isn't ahead of the tail, we don't have any characters
|
if (_rx_buffer->_iHead == _rx_buffer->_iTail)
|
||||||
if ( _rx_buffer->_iHead == _rx_buffer->_iTail )
|
return -1;
|
||||||
return -1 ;
|
|
||||||
|
|
||||||
uint8_t uc = _rx_buffer->_aucBuffer[_rx_buffer->_iTail] ;
|
|
||||||
_rx_buffer->_iTail = (unsigned int)(_rx_buffer->_iTail + 1) % SERIAL_BUFFER_SIZE ;
|
|
||||||
return uc ;
|
|
||||||
|
|
||||||
|
uint8_t uc = _rx_buffer->_aucBuffer[_rx_buffer->_iTail];
|
||||||
|
_rx_buffer->_iTail = (unsigned int)(_rx_buffer->_iTail + 1) % SERIAL_BUFFER_SIZE;
|
||||||
|
return uc;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LOGUARTClass::flush( void )
|
void LOGUARTClass::flush(void) {
|
||||||
{
|
// TODO:
|
||||||
// TODO:
|
// while ( serial_writable(&(this->sobj)) != 1 );
|
||||||
// while ( serial_writable(&(this->sobj)) != 1 );
|
/*
|
||||||
/*
|
// Wait for transmission to complete
|
||||||
// Wait for transmission to complete
|
while ((_pUart->UART_SR & UART_SR_TXRDY) != UART_SR_TXRDY)
|
||||||
while ((_pUart->UART_SR & UART_SR_TXRDY) != UART_SR_TXRDY)
|
;
|
||||||
;
|
*/
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t LOGUARTClass::write( const uint8_t uc_data )
|
size_t LOGUARTClass::write(const uint8_t uc_data) {
|
||||||
{
|
DiagPutChar(uc_data);
|
||||||
DiagPutChar(uc_data);
|
return 1;
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LOGUARTClass Serial(UART_LOG_IRQ, &rx_buffer0);
|
LOGUARTClass Serial(UART_LOG_IRQ, &rx_buffer0);
|
||||||
|
|
||||||
bool Serial_available() {
|
bool Serial_available() {
|
||||||
return Serial.available() > 0;
|
return Serial.available() > 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
This library is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
See the GNU Lesser General Public License for more details.
|
See the GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
@@ -18,36 +18,41 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "api/HardwareSerial.h"
|
#include <api/HardwareSerial.h>
|
||||||
#include "api/RingBuffer.h"
|
#include <api/RingBuffer.h>
|
||||||
|
|
||||||
using namespace arduino;
|
using namespace arduino;
|
||||||
|
|
||||||
class LOGUARTClass : public HardwareSerial
|
// TODO this class begs to be rewritten :(
|
||||||
{
|
|
||||||
|
class LOGUARTClass : public HardwareSerial {
|
||||||
public:
|
public:
|
||||||
LOGUARTClass(int dwIrq, RingBuffer* pRx_buffer );
|
LOGUARTClass(int dwIrq, RingBuffer *pRx_buffer);
|
||||||
|
|
||||||
void begin(const uint32_t dwBaudRate);
|
void begin(const uint32_t dwBaudRate);
|
||||||
inline void begin(const uint32_t dwBaudRate, uint16_t config) {
|
|
||||||
begin(dwBaudRate); // TODO implement this properly
|
|
||||||
}
|
|
||||||
void end(void);
|
|
||||||
int available(void);
|
|
||||||
int peek(void);
|
|
||||||
int read(void);
|
|
||||||
void flush(void);
|
|
||||||
size_t write(const uint8_t c);
|
|
||||||
|
|
||||||
using Print::write; // pull in write(str) and write(buf, size) from Print
|
inline void begin(const uint32_t dwBaudRate, uint16_t config) {
|
||||||
|
begin(dwBaudRate); // TODO implement this properly
|
||||||
|
}
|
||||||
|
|
||||||
operator bool() { return true; }; // UART always active
|
void end(void);
|
||||||
|
int available(void);
|
||||||
|
int peek(void);
|
||||||
|
int read(void);
|
||||||
|
void flush(void);
|
||||||
|
size_t write(const uint8_t c);
|
||||||
|
|
||||||
|
using Print::write; // pull in write(str) and write(buf, size) from Print
|
||||||
|
|
||||||
|
operator bool() {
|
||||||
|
return true; // UART always active
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
RingBuffer *_rx_buffer;
|
RingBuffer *_rx_buffer;
|
||||||
|
|
||||||
int _dwIrq;
|
int _dwIrq;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend bool Serial_available();
|
friend bool Serial_available();
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,76 +0,0 @@
|
|||||||
#ifndef _POWER_MANAGEMENT_H_
|
|
||||||
#define _POWER_MANAGEMENT_H_
|
|
||||||
|
|
||||||
#include <inttypes.h>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @class PowerManagementClass PowerManagement.h
|
|
||||||
* @brief Power management in Ameba
|
|
||||||
*/
|
|
||||||
class PowerManagementClass {
|
|
||||||
public:
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Allow OS automatically save power while idle
|
|
||||||
*
|
|
||||||
* As OS consider it would idle for more than 2s, it will invoke system suspend.
|
|
||||||
* If wlan is associated with AP, than it will under asslociated idle state.
|
|
||||||
*/
|
|
||||||
static void sleep(void);
|
|
||||||
static void sleep(uint32_t bitflg);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Disallow OS automatically save power while idle
|
|
||||||
*/
|
|
||||||
static void active(void);
|
|
||||||
static void active(uint32_t bitflg);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Reserved PLL while sleep
|
|
||||||
*
|
|
||||||
* Reserve PLL would keep FIFO of peripherals (Ex. UART) but cost more power (around 5mA).
|
|
||||||
* If we don't reserve PLL, it saves more power but we might missing data because FIFO is turned of this way.
|
|
||||||
*
|
|
||||||
* @param[in] reserve true for reserved, false for non-reserved
|
|
||||||
*/
|
|
||||||
static void setPllReserved(bool reserve);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Enter deepsleep immediately
|
|
||||||
*
|
|
||||||
* Invoke deepsleep would make system enter deepsleep state immediately.
|
|
||||||
* It's the state that saves most power.
|
|
||||||
* As it wakeup from deepsleep, the system would behave just like reboot.
|
|
||||||
*
|
|
||||||
* @param[in] duration_ms wakeup after specific time in unit of millisecond
|
|
||||||
*/
|
|
||||||
static void deepsleep(uint32_t duration_ms);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Check if system is allowed enter any power save state
|
|
||||||
*
|
|
||||||
* The pin 18 (GPIOE_5) is designed as safe lock.
|
|
||||||
* If pin 18 is HIGH, then we prevent Ameba enter any power save state.\n\n
|
|
||||||
* Under any power save state, we are not able to flash image to Ameba.
|
|
||||||
* Thus if user misuse deepsleep and make Ameba enter deepsleep immediately after boot up,
|
|
||||||
* then he would find it's hard to flash image.
|
|
||||||
* In this case, he can pull up pin 18.
|
|
||||||
*
|
|
||||||
* @return true if system not allowed enter any power save state, and false vise versa
|
|
||||||
*/
|
|
||||||
static bool safeLock();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Reboot system
|
|
||||||
*
|
|
||||||
* Reboot system in soft way. Some registers is not powered off in this case, but mostly we could regard this as reboot.
|
|
||||||
*/
|
|
||||||
static void softReset();
|
|
||||||
|
|
||||||
private:
|
|
||||||
static bool reservePLL;
|
|
||||||
};
|
|
||||||
|
|
||||||
extern PowerManagementClass PowerManagement;
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,17 +1,12 @@
|
|||||||
#if 1 // !defined(BOARD_RTL8710)
|
#include <Arduino.h>
|
||||||
|
|
||||||
#include "Arduino.h"
|
extern void pinRemoveMode(pin_size_t pinNumber);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
extern void _tone(uint32_t ulPin, unsigned int frequency, unsigned long duration);
|
extern void _tone(uint32_t ulPin, unsigned int frequency, unsigned long duration);
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// a wrapper that support default value of duration
|
void tone(uint32_t ulPin, unsigned int frequency, unsigned long duration) {
|
||||||
void tone(uint32_t ulPin, unsigned int frequency, unsigned long duration)
|
_tone(ulPin, frequency, duration);
|
||||||
{
|
|
||||||
_tone(ulPin, frequency, duration);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
void noTone(uint32_t ulPin) {
|
||||||
|
pinRemoveMode(ulPin);
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,16 +1,14 @@
|
|||||||
#include "Arduino.h"
|
#include <Arduino.h>
|
||||||
|
#include <gpio_api.h>
|
||||||
#ifdef __cplusplus
|
#include <gpio_irq_api.h>
|
||||||
extern "C" {
|
#include <gpio_irq_ex_api.h>
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "gpio_api.h"
|
|
||||||
#include "gpio_irq_api.h"
|
|
||||||
#include "gpio_irq_ex_api.h"
|
|
||||||
|
|
||||||
extern void *gpio_pin_struct[PINS_COUNT];
|
extern void *gpio_pin_struct[PINS_COUNT];
|
||||||
extern void *gpio_irq_handler_list[PINS_COUNT];
|
extern void *gpio_irq_handler_list[PINS_COUNT];
|
||||||
|
|
||||||
|
extern bool pinInvalid(pin_size_t pinNumber);
|
||||||
|
extern void pinRemoveMode(pin_size_t pinNumber);
|
||||||
|
|
||||||
void gpioIrqHandler(uint32_t id, gpio_irq_event event) {
|
void gpioIrqHandler(uint32_t id, gpio_irq_event event) {
|
||||||
if (gpio_irq_handler_list[id] != NULL) {
|
if (gpio_irq_handler_list[id] != NULL) {
|
||||||
((void (*)(uint32_t, uint32_t))gpio_irq_handler_list[id])(id, (uint32_t)event);
|
((void (*)(uint32_t, uint32_t))gpio_irq_handler_list[id])(id, (uint32_t)event);
|
||||||
@@ -36,7 +34,7 @@ void attachInterrupt(pin_size_t interruptNumber, voidFuncPtr callback, PinStatus
|
|||||||
|
|
||||||
if (g_APinDescription[interruptNumber].ulPinType == NOT_INITIAL) {
|
if (g_APinDescription[interruptNumber].ulPinType == NOT_INITIAL) {
|
||||||
// allocate memory if pin not used before
|
// allocate memory if pin not used before
|
||||||
gpio = malloc(sizeof(gpio_irq_t));
|
gpio = malloc(sizeof(gpio_irq_t));
|
||||||
gpio_pin_struct[interruptNumber] = gpio;
|
gpio_pin_struct[interruptNumber] = gpio;
|
||||||
gpio_irq_init(gpio, g_APinDescription[interruptNumber].pinname, gpioIrqHandler, interruptNumber);
|
gpio_irq_init(gpio, g_APinDescription[interruptNumber].pinname, gpioIrqHandler, interruptNumber);
|
||||||
g_APinDescription[interruptNumber].ulPinType = PIO_GPIO_IRQ;
|
g_APinDescription[interruptNumber].ulPinType = PIO_GPIO_IRQ;
|
||||||
@@ -78,7 +76,3 @@ void detachInterrupt(pin_size_t interruptNumber) {
|
|||||||
}
|
}
|
||||||
gpio_irq_handler_list[interruptNumber] = NULL;
|
gpio_irq_handler_list[interruptNumber] = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|||||||
@@ -1,77 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright (c) 2011 Arduino. All right reserved.
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
See the GNU Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <inttypes.h>
|
|
||||||
#include "api/Common.h"
|
|
||||||
|
|
||||||
extern "C" {
|
|
||||||
extern void rtl_srandom( uint32_t seed );
|
|
||||||
extern uint32_t rtl_random( void );
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef srand
|
|
||||||
#define srand rtl_srandom
|
|
||||||
#endif
|
|
||||||
#ifndef rand
|
|
||||||
#define rand rtl_random
|
|
||||||
#endif
|
|
||||||
|
|
||||||
extern void randomSeed( uint32_t dwSeed )
|
|
||||||
{
|
|
||||||
if ( dwSeed != 0 )
|
|
||||||
{
|
|
||||||
srand( dwSeed ) ;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extern long random( long howbig )
|
|
||||||
{
|
|
||||||
if ( howbig == 0 )
|
|
||||||
{
|
|
||||||
return 0 ;
|
|
||||||
}
|
|
||||||
|
|
||||||
return rand() % howbig;
|
|
||||||
}
|
|
||||||
|
|
||||||
extern long random( long howsmall, long howbig )
|
|
||||||
{
|
|
||||||
if (howsmall >= howbig)
|
|
||||||
{
|
|
||||||
return howsmall;
|
|
||||||
}
|
|
||||||
|
|
||||||
long diff = howbig - howsmall;
|
|
||||||
|
|
||||||
return random(diff) + howsmall;
|
|
||||||
}
|
|
||||||
|
|
||||||
extern long map(long x, long in_min, long in_max, long out_min, long out_max)
|
|
||||||
{
|
|
||||||
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
|
|
||||||
}
|
|
||||||
|
|
||||||
extern uint16_t makeWord( uint16_t w )
|
|
||||||
{
|
|
||||||
return w ;
|
|
||||||
}
|
|
||||||
|
|
||||||
extern uint16_t makeWord( uint8_t h, uint8_t l )
|
|
||||||
{
|
|
||||||
return (h << 8) | l ;
|
|
||||||
}
|
|
||||||
@@ -1,118 +1,60 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "wiring_os.h"
|
#include <stdarg.h>
|
||||||
#include "wiring_watchdog.h"
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <stddef.h>
|
#include "sdk_extern.h"
|
||||||
#include <stdint.h>
|
#include "sdk_mem.h"
|
||||||
#include <stdarg.h>
|
#include "sdk_os.h"
|
||||||
#define boolean boolean_rtl
|
|
||||||
#include "rtl_lib.h"
|
|
||||||
#include "rand.h"
|
|
||||||
#include "rt_lib_rom.h"
|
|
||||||
#undef boolean
|
|
||||||
|
|
||||||
/* moved from Arduino.h */
|
#define NOT_INITIAL (1UL << 0)
|
||||||
/*
|
#define PIO_GPIO (1UL << 1)
|
||||||
* \brief Set CPU CLK 166MHz
|
#define PIO_PWM (1UL << 2)
|
||||||
* clk : 0 - 166666666 Hz, 1 - 83333333 Hz, 2 - 41666666 Hz, 3 - 20833333 Hz, 4 - 10416666 Hz, 5 - 4000000 Hz
|
#define PIO_I2C (1UL << 3)
|
||||||
* baud: 38400,...
|
#define PIO_ADC (1UL << 4)
|
||||||
*/
|
#define PIO_DAC (1UL << 5)
|
||||||
extern void Init_CPU_CLK_UART(int clkn, int baud);
|
#define PIO_GPIO_IRQ (1UL << 6)
|
||||||
extern void sys_info(void);
|
|
||||||
/* HalGetChipId:
|
|
||||||
* 0xff - RTL8711AM, 0xfe - RTL8195AM, 0xfd - RTL8711AF,
|
|
||||||
* 0xfc - RTL8710AF, 0xfb - RTL8711AN, 0xfa - RTL8710AM */
|
|
||||||
extern unsigned char HalGetChipId(void);
|
|
||||||
extern unsigned int HalGetCpuClk(void);
|
|
||||||
|
|
||||||
extern void wait_us(int us);
|
|
||||||
#define delay_us wait_us
|
|
||||||
|
|
||||||
extern void yield(void);
|
|
||||||
|
|
||||||
extern void *pvPortMalloc(size_t xWantedSize);
|
|
||||||
extern void *pvPortZalloc(size_t size);
|
|
||||||
extern void *pvPortCalloc(size_t nmemb, size_t size);
|
|
||||||
extern void *pvPortReAlloc(void *pv, size_t xWantedSize);
|
|
||||||
extern void vPortFree(void *pv);
|
|
||||||
|
|
||||||
#define malloc pvPortMalloc
|
|
||||||
#define zalloc pvPortZalloc
|
|
||||||
#define calloc pvPortCalloc
|
|
||||||
#define realloc pvPortReAlloc
|
|
||||||
#define free vPortFree
|
|
||||||
|
|
||||||
#ifndef printf
|
|
||||||
#define printf rtl_printf
|
|
||||||
#endif
|
|
||||||
#ifndef sprintf
|
|
||||||
#define sprintf rtl_sprintf
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define NOT_INITIAL (1UL<<0)
|
|
||||||
#define PIO_GPIO (1UL<<1)
|
|
||||||
#define PIO_PWM (1UL<<2)
|
|
||||||
#define PIO_I2C (1UL<<3)
|
|
||||||
#define PIO_ADC (1UL<<4)
|
|
||||||
#define PIO_DAC (1UL<<5)
|
|
||||||
#define PIO_GPIO_IRQ (1UL<<6)
|
|
||||||
|
|
||||||
#define PWM_MODE_ENABLED 1
|
#define PWM_MODE_ENABLED 1
|
||||||
#define PWM_MODE_DISABLED 0
|
#define PWM_MODE_DISABLED 0
|
||||||
|
|
||||||
/* Types used for the tables below */
|
#define DEFAULT 1
|
||||||
typedef struct _PinDescription
|
|
||||||
{
|
|
||||||
// HW PinNames
|
|
||||||
uint32_t pinname;
|
|
||||||
// Current Pin Type
|
|
||||||
uint32_t ulPinType;
|
|
||||||
// Supported Pin Function
|
|
||||||
uint32_t ulPinAttribute;
|
|
||||||
// Current Pin Mode
|
|
||||||
uint32_t ulPinMode;
|
|
||||||
} PinDescription ;
|
|
||||||
|
|
||||||
/* Pins table to be instanciated into variant.cpp */
|
|
||||||
extern PinDescription g_APinDescription[];
|
|
||||||
|
|
||||||
extern bool pinInvalid(pin_size_t pinNumber);
|
|
||||||
extern void pinRemoveMode(pin_size_t pinNumber);
|
|
||||||
|
|
||||||
/* moved from wiring_digital.h */
|
|
||||||
/**************************** Extend API by RTK ***********************************/
|
|
||||||
extern uint32_t digitalPinToPort( uint32_t pinNumber );
|
|
||||||
extern uint32_t digitalPinToBitMask( uint32_t pinNumber );
|
|
||||||
|
|
||||||
/* moved from wiring_analog.h */
|
|
||||||
/*
|
|
||||||
* \brief Set the resolution of analogRead return values. Default is 10 bits (range from 0 to 1023).
|
|
||||||
*
|
|
||||||
* \param res
|
|
||||||
*/
|
|
||||||
extern void analogReadResolution(int res);
|
|
||||||
/*
|
|
||||||
* \brief Set the resolution of analogWrite parameters. Default is 8 bits (range from 0 to 255).
|
|
||||||
*
|
|
||||||
* \param res
|
|
||||||
*/
|
|
||||||
extern void analogWriteResolution(int res);
|
|
||||||
extern void analogOutputInit( void ) ;
|
|
||||||
extern void analogWritePeriod(int us);
|
|
||||||
|
|
||||||
/* moved from wiring_constants.h */
|
|
||||||
#define DEFAULT 1
|
|
||||||
#define EXTERNAL 0
|
#define EXTERNAL 0
|
||||||
|
|
||||||
#define round(x) ((x)>=0?(long)((x)+0.5):(long)((x)-0.5))
|
#define round(x) ((x) >= 0 ? (long)((x) + 0.5) : (long)((x)-0.5))
|
||||||
|
|
||||||
extern uint32_t ulPortSetInterruptMask( void );
|
typedef enum _eAnalogReference {
|
||||||
extern void vPortClearInterruptMask( uint32_t ulNewMask );
|
AR_DEFAULT,
|
||||||
|
} eAnalogReference;
|
||||||
|
|
||||||
|
// Types used for the table below
|
||||||
|
typedef struct _PinDescription {
|
||||||
|
// HW PinNames
|
||||||
|
uint32_t pinname;
|
||||||
|
// Current Pin Type
|
||||||
|
uint32_t ulPinType;
|
||||||
|
// Supported Pin Function
|
||||||
|
uint32_t ulPinAttribute;
|
||||||
|
// Current Pin Mode
|
||||||
|
uint32_t ulPinMode;
|
||||||
|
} PinDescription;
|
||||||
|
|
||||||
|
// Pins table to be instantiated into variant.cpp
|
||||||
|
extern PinDescription g_APinDescription[];
|
||||||
|
|
||||||
|
// Additional Wiring functions
|
||||||
|
extern uint32_t digitalPinToPort(uint32_t pinNumber);
|
||||||
|
extern uint32_t digitalPinToBitMask(uint32_t pinNumber);
|
||||||
|
extern void analogReadResolution(int res);
|
||||||
|
extern void analogWriteResolution(int res);
|
||||||
|
extern void analogOutputInit(void);
|
||||||
|
extern void analogWritePeriod(int us);
|
||||||
|
extern void wait_for_debug();
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
|
|||||||
@@ -1,100 +0,0 @@
|
|||||||
/*
|
|
||||||
* WebSocketClient + SSL/TSL
|
|
||||||
* RTL8710AF pvvx 12/12/2016
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "Arduino.h"
|
|
||||||
#include "WebSocketClient.h"
|
|
||||||
|
|
||||||
WebSocketClient::WebSocketClient() {
|
|
||||||
}
|
|
||||||
|
|
||||||
WebSocketClient::WebSocketClient(char *url, int port, char *path, char* origin) {
|
|
||||||
client = create_wsclient(url, port, path, origin);
|
|
||||||
}
|
|
||||||
|
|
||||||
WebSocketClient::~WebSocketClient() {
|
|
||||||
close();
|
|
||||||
}
|
|
||||||
|
|
||||||
int WebSocketClient::begin(char *url, int port, char *path, char* origin) {
|
|
||||||
client = create_wsclient(url, port, path, origin);
|
|
||||||
if(client != NULL) return 1;
|
|
||||||
else return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int WebSocketClient::connect() {
|
|
||||||
if(client != NULL) return ws_connect_url(client);
|
|
||||||
else return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void WebSocketClient::send(char* message, int message_len, int use_mask) {
|
|
||||||
if(client != NULL && client->readyState > CLOSED) {
|
|
||||||
ws_send(message, message_len, use_mask, client);
|
|
||||||
ws_poll(0, client);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void WebSocketClient::sendBinary(uint8_t* message, int message_len, int use_mask) {
|
|
||||||
if(client != NULL && client->readyState > CLOSED) {
|
|
||||||
ws_sendBinary(message, message_len, use_mask, client);
|
|
||||||
ws_poll(0, client);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void WebSocketClient::sendPing() {
|
|
||||||
if(client != NULL && client->readyState > CLOSED) {
|
|
||||||
ws_sendPing(client);
|
|
||||||
ws_poll(0, client);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void WebSocketClient::poll(int timeout) {
|
|
||||||
if(client != NULL) ws_poll(timeout, client);
|
|
||||||
}
|
|
||||||
|
|
||||||
readyStateValues WebSocketClient::getReadyState() {
|
|
||||||
if(client != NULL) return ws_getReadyState(client);
|
|
||||||
else return CLOSED;
|
|
||||||
}
|
|
||||||
|
|
||||||
void WebSocketClient::dispatch(void (*callback)(wsclient_context *, int))
|
|
||||||
{
|
|
||||||
if(client != NULL) ws_dispatch(callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WebSocketClient::close() {
|
|
||||||
if(client != NULL) {
|
|
||||||
ws_close(client);
|
|
||||||
if(client->ssl) {
|
|
||||||
free(client->ssl);
|
|
||||||
client->ssl = NULL;
|
|
||||||
}
|
|
||||||
client = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" void set_ssl_func(wsclient_context *wsclient); // in example_wsclient.c
|
|
||||||
|
|
||||||
void WebSocketClient::ssl_func_on(void)
|
|
||||||
{
|
|
||||||
set_ssl_func(client);
|
|
||||||
/*
|
|
||||||
client->fun_ops.ssl_fun_ops.memory_set_own = memory_set_own;
|
|
||||||
client->fun_ops.ssl_fun_ops.net_connect = net_connect;
|
|
||||||
client->fun_ops.ssl_fun_ops.ssl_init = ssl_init;
|
|
||||||
client->fun_ops.ssl_fun_ops.ssl_set_endpoint = ssl_set_endpoint;
|
|
||||||
client->fun_ops.ssl_fun_ops.ssl_set_authmode = ssl_set_authmode;
|
|
||||||
client->fun_ops.ssl_fun_ops.ssl_set_rng = ssl_set_rng;
|
|
||||||
client->fun_ops.ssl_fun_ops.ssl_set_bio = ssl_set_bio;
|
|
||||||
client->fun_ops.ssl_fun_ops.ssl_handshake = ssl_handshake;
|
|
||||||
client->fun_ops.ssl_fun_ops.net_close = net_close;
|
|
||||||
client->fun_ops.ssl_fun_ops.ssl_free = ssl_free;
|
|
||||||
client->fun_ops.ssl_fun_ops.ssl_read = ssl_read;
|
|
||||||
client->fun_ops.ssl_fun_ops.ssl_write = ssl_write;
|
|
||||||
client->fun_ops.ssl_fun_ops.net_recv = net_recv;
|
|
||||||
client->fun_ops.ssl_fun_ops.net_send = net_send;
|
|
||||||
client->ssl = (void *)zalloc(sizeof(struct _ssl_context)); // 380 bytes
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
@@ -1,116 +0,0 @@
|
|||||||
/*
|
|
||||||
* WebSocketClient + SSL/TSL
|
|
||||||
* RTL8710AF pvvx 12/12/2016
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
#ifndef WEBSOCKETCLIENT_H_
|
|
||||||
#define WEBSOCKETCLIENT_H_
|
|
||||||
|
|
||||||
#include <Arduino.h>
|
|
||||||
extern "C" {
|
|
||||||
#include "libwsclient.h"
|
|
||||||
#include "wsclient_api.h"
|
|
||||||
}
|
|
||||||
|
|
||||||
class WebSocketClient {
|
|
||||||
public:
|
|
||||||
WebSocketClient();
|
|
||||||
~WebSocketClient();
|
|
||||||
|
|
||||||
/*************************************************************************************************
|
|
||||||
** Function Name : begin
|
|
||||||
** Description : Creating the websocket client context structure
|
|
||||||
** Input : url:websocket server's url
|
|
||||||
** port:websocket server's port, if not given, default 80 for "ws", 443 for "wss"
|
|
||||||
** origin: the address or url of your self
|
|
||||||
** Return : Ok: 1
|
|
||||||
** Failed: 0
|
|
||||||
**************************************************************************************************/
|
|
||||||
WebSocketClient(char *url, int port, char *path = NULL, char* origin = NULL);
|
|
||||||
int begin(char *url, int port, char *path = NULL, char* origin = NULL);
|
|
||||||
|
|
||||||
/*************************************************************************************************
|
|
||||||
** Function Name : connect
|
|
||||||
** Description : Connecting to the websocket server
|
|
||||||
** Input : wsclient: the websocket client context created by create_wsclientfunction
|
|
||||||
** Return : Connected: the socket value
|
|
||||||
** Failed: -1
|
|
||||||
**************************************************************************************************/
|
|
||||||
int connect();
|
|
||||||
|
|
||||||
/*************************************************************************************************
|
|
||||||
** Function Name : ws_send
|
|
||||||
** Description : Create the sending string data and copy to tx_buf
|
|
||||||
** Input : message: the string that send to server(cannot exceeding the MAX_DATA_LEN
|
|
||||||
** message_len: the length of the string
|
|
||||||
** use_mask: 0/1; 1 means using mask for bynary
|
|
||||||
** wsclient: the websocket client context
|
|
||||||
** Return : None
|
|
||||||
**************************************************************************************************/
|
|
||||||
void send(char* message, int message_len, int use_mask);
|
|
||||||
|
|
||||||
/*************************************************************************************************
|
|
||||||
** Function Name : sendBinary
|
|
||||||
** Description : Create the sending binary data and copy to tx_buf
|
|
||||||
** Input : message: the binary that send to server(cannot exceeding the MAX_DATA_LEN
|
|
||||||
** message_len: the length of the binary
|
|
||||||
** use_mask: 0/1; 1 means using mask for bynary
|
|
||||||
** wsclient: the websocket client context
|
|
||||||
** Return : None
|
|
||||||
**************************************************************************************************/
|
|
||||||
void sendBinary(uint8_t* message, int message_len, int use_mask);
|
|
||||||
|
|
||||||
/*************************************************************************************************
|
|
||||||
** Function Name : sendPing
|
|
||||||
** Description : Sending Ping to websocket server
|
|
||||||
** Input : wsclient: the websocket client context
|
|
||||||
** Return : None
|
|
||||||
**************************************************************************************************/
|
|
||||||
void sendPing();
|
|
||||||
|
|
||||||
/*************************************************************************************************
|
|
||||||
** Function Name : poll
|
|
||||||
** Description : Receicing data from server and send the data in tx_buf
|
|
||||||
** Input : timeout(in milliseconds)
|
|
||||||
wsclient: the websocket client context
|
|
||||||
** Return : None
|
|
||||||
**************************************************************************************************/
|
|
||||||
void poll(int timeout);
|
|
||||||
|
|
||||||
/*************************************************************************************************
|
|
||||||
** Function Name : dispatch
|
|
||||||
** Description : callback function when getting message from server
|
|
||||||
** Input : function that resolve the message received and the message length
|
|
||||||
** Return : None
|
|
||||||
**************************************************************************************************/
|
|
||||||
void dispatch(void (*callback)(wsclient_context *, int));
|
|
||||||
|
|
||||||
/*************************************************************************************************
|
|
||||||
** Function Name : getReadyState
|
|
||||||
** Description : Getting the connection status
|
|
||||||
** Input : wsclient: the websocket client context
|
|
||||||
** Return : readyStateValues(4 types: CLOSING, CLOSED, CONNECTING, OPEN )
|
|
||||||
**************************************************************************************************/
|
|
||||||
readyStateValues getReadyState();
|
|
||||||
|
|
||||||
/*************************************************************************************************
|
|
||||||
** Function Name : close
|
|
||||||
** Description : Closing the connection with websocket server
|
|
||||||
** Input : wsclient: the websocket client context
|
|
||||||
** Return : None
|
|
||||||
**************************************************************************************************/
|
|
||||||
void close();
|
|
||||||
|
|
||||||
/*************************************************************************************************
|
|
||||||
** Function Name : ssl_func_on
|
|
||||||
** Description : Set SSL/TSL function
|
|
||||||
** Input : None
|
|
||||||
** Return : None
|
|
||||||
**************************************************************************************************/
|
|
||||||
void ssl_func_on(void);
|
|
||||||
|
|
||||||
private:
|
|
||||||
wsclient_context *client;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // WEBSOCKETCLIENT_H_
|
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
// Simple Base64 code
|
|
||||||
// (c) Copyright 2010 MCQN Ltd.
|
|
||||||
// Released under Apache License, version 2.0
|
|
||||||
|
|
||||||
#include "b64.h"
|
|
||||||
|
|
||||||
/* Simple test program
|
|
||||||
#include <stdio.h>
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
char* in = "amcewen";
|
|
||||||
char out[22];
|
|
||||||
|
|
||||||
b64_encode(in, 15, out, 22);
|
|
||||||
out[21] = '\0';
|
|
||||||
|
|
||||||
printf(out);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
int b64_encode(const unsigned char* aInput, int aInputLen, unsigned char* aOutput, int aOutputLen)
|
|
||||||
{
|
|
||||||
// Work out if we've got enough space to encode the input
|
|
||||||
// Every 6 bits of input becomes a byte of output
|
|
||||||
if (aOutputLen < (aInputLen*8)/6)
|
|
||||||
{
|
|
||||||
// FIXME Should we return an error here, or just the length
|
|
||||||
return (aInputLen*8)/6;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we get here we've got enough space to do the encoding
|
|
||||||
|
|
||||||
const char* b64_dictionary = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
||||||
if (aInputLen == 3)
|
|
||||||
{
|
|
||||||
aOutput[0] = b64_dictionary[aInput[0] >> 2];
|
|
||||||
aOutput[1] = b64_dictionary[(aInput[0] & 0x3)<<4|(aInput[1]>>4)];
|
|
||||||
aOutput[2] = b64_dictionary[(aInput[1]&0x0F)<<2|(aInput[2]>>6)];
|
|
||||||
aOutput[3] = b64_dictionary[aInput[2]&0x3F];
|
|
||||||
}
|
|
||||||
else if (aInputLen == 2)
|
|
||||||
{
|
|
||||||
aOutput[0] = b64_dictionary[aInput[0] >> 2];
|
|
||||||
aOutput[1] = b64_dictionary[(aInput[0] & 0x3)<<4|(aInput[1]>>4)];
|
|
||||||
aOutput[2] = b64_dictionary[(aInput[1]&0x0F)<<2];
|
|
||||||
aOutput[3] = '=';
|
|
||||||
}
|
|
||||||
else if (aInputLen == 1)
|
|
||||||
{
|
|
||||||
aOutput[0] = b64_dictionary[aInput[0] >> 2];
|
|
||||||
aOutput[1] = b64_dictionary[(aInput[0] & 0x3)<<4];
|
|
||||||
aOutput[2] = '=';
|
|
||||||
aOutput[3] = '=';
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Break the input into 3-byte chunks and process each of them
|
|
||||||
int i;
|
|
||||||
for (i = 0; i < aInputLen/3; i++)
|
|
||||||
{
|
|
||||||
b64_encode(&aInput[i*3], 3, &aOutput[i*4], 4);
|
|
||||||
}
|
|
||||||
if (aInputLen % 3 > 0)
|
|
||||||
{
|
|
||||||
// It doesn't fit neatly into a 3-byte chunk, so process what's left
|
|
||||||
b64_encode(&aInput[i*3], aInputLen % 3, &aOutput[i*4], aOutputLen - (i*4));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
#ifndef b64_h
|
|
||||||
#define b64_h
|
|
||||||
|
|
||||||
int b64_encode(const unsigned char* aInput, int aInputLen, unsigned char* aOutput, int aOutputLen);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright (c) 2011 Arduino. All right reserved.
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
See the GNU Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
extern "C" void __cxa_pure_virtual(void) ;
|
|
||||||
|
|
||||||
/* We compile with nodefaultlibs, so we need to provide an error
|
|
||||||
* handler for an empty pure virtual function */
|
|
||||||
extern "C" void __cxa_pure_virtual(void) {
|
|
||||||
while(1)
|
|
||||||
;
|
|
||||||
}
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
#ifndef ARD_DEBUG_H
|
|
||||||
#define ARD_DEBUG_H
|
|
||||||
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
#ifdef DEBUG_RTL_CORE
|
|
||||||
#define DEBUGV(...) rtl_printf(__VA_ARGS__)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef DEBUGV
|
|
||||||
#define DEBUGV(...)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
void hexdump(void * addr, int len = 16);
|
|
||||||
#else
|
|
||||||
void hexdump(void * addr, int len);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
void print_udp_pcb(void);
|
|
||||||
void print_tcp_pcb(void);
|
|
||||||
void DumpForOneBytes(void *addr, int cnt); // cnt max 0x70 !
|
|
||||||
|
|
||||||
void __panic_func(const char* file, int line, const char* func) __attribute__((noreturn));
|
|
||||||
#define panic() __panic_func(__FILE__, __LINE__, __func__)
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#endif//ARD_DEBUG_H
|
|
||||||
@@ -1,116 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright (c) 2011 Arduino. All right reserved.
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
See the GNU Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "api/itoa.h"
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C"{
|
|
||||||
#endif // __cplusplus
|
|
||||||
|
|
||||||
extern char* ltoa(long value, char *string, int radix)
|
|
||||||
{
|
|
||||||
char tmp[33];
|
|
||||||
char *tp = tmp;
|
|
||||||
long i;
|
|
||||||
unsigned long v;
|
|
||||||
int sign;
|
|
||||||
char *sp;
|
|
||||||
|
|
||||||
if ( string == NULL )
|
|
||||||
{
|
|
||||||
return 0 ;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (radix > 36 || radix <= 1)
|
|
||||||
{
|
|
||||||
return 0 ;
|
|
||||||
}
|
|
||||||
|
|
||||||
sign = (radix == 10 && value < 0);
|
|
||||||
if (sign)
|
|
||||||
{
|
|
||||||
v = -value;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
v = (unsigned long)value;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (v || tp == tmp)
|
|
||||||
{
|
|
||||||
i = v % radix;
|
|
||||||
v = v / radix;
|
|
||||||
if (i < 10)
|
|
||||||
*tp++ = i+'0';
|
|
||||||
else
|
|
||||||
*tp++ = i + 'a' - 10;
|
|
||||||
}
|
|
||||||
|
|
||||||
sp = string;
|
|
||||||
|
|
||||||
if (sign)
|
|
||||||
*sp++ = '-';
|
|
||||||
while (tp > tmp)
|
|
||||||
*sp++ = *--tp;
|
|
||||||
*sp = 0;
|
|
||||||
|
|
||||||
return string;
|
|
||||||
}
|
|
||||||
|
|
||||||
extern char* ultoa(unsigned long value, char *string, int radix)
|
|
||||||
{
|
|
||||||
char tmp[33];
|
|
||||||
char *tp = tmp;
|
|
||||||
long i;
|
|
||||||
unsigned long v = value;
|
|
||||||
char *sp;
|
|
||||||
|
|
||||||
if ( string == NULL )
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (radix > 36 || radix <= 1)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (v || tp == tmp)
|
|
||||||
{
|
|
||||||
i = v % radix;
|
|
||||||
v = v / radix;
|
|
||||||
if (i < 10)
|
|
||||||
*tp++ = i+'0';
|
|
||||||
else
|
|
||||||
*tp++ = i + 'a' - 10;
|
|
||||||
}
|
|
||||||
|
|
||||||
sp = string;
|
|
||||||
|
|
||||||
|
|
||||||
while (tp > tmp)
|
|
||||||
*sp++ = *--tp;
|
|
||||||
*sp = 0;
|
|
||||||
|
|
||||||
return string;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
} // extern "C"
|
|
||||||
#endif // __cplusplus
|
|
||||||
@@ -1,120 +0,0 @@
|
|||||||
#ifndef EASYWSCLIENT_H
|
|
||||||
#define EASYWSCLIENT_H
|
|
||||||
#include <platform/platform_stdlib.h>
|
|
||||||
|
|
||||||
/****************Define the debug message level*********************/
|
|
||||||
#define DEBUG_WSCLIENT 1
|
|
||||||
|
|
||||||
#define WSCLIENT_LOG(level, fmt, ...) printf("\n\r[WSCLIENT %s] %s: " fmt "\n", level, __FUNCTION__, ##__VA_ARGS__)
|
|
||||||
#if DEBUG_WSCLIENT == 2
|
|
||||||
#define WSCLIENT_DEBUG(fmt, ...) WSCLIENT_LOG("DEBUG", fmt, ##__VA_ARGS__)
|
|
||||||
#else
|
|
||||||
#define WSCLIENT_DEBUG(fmt, ...)
|
|
||||||
#endif
|
|
||||||
#if DEBUG_WSCLIENT
|
|
||||||
#define WSCLIENT_ERROR(fmt, ...) WSCLIENT_LOG("ERROR", fmt, ##__VA_ARGS__)
|
|
||||||
#else
|
|
||||||
#define WSCLIENT_ERROR(fmt, ...)
|
|
||||||
#endif
|
|
||||||
/*******************************************************************/
|
|
||||||
|
|
||||||
/****************Define the structures used*************************/
|
|
||||||
typedef enum{
|
|
||||||
CLOSING,
|
|
||||||
CLOSED,
|
|
||||||
CONNECTING,
|
|
||||||
OPEN
|
|
||||||
} readyStateValues;
|
|
||||||
|
|
||||||
struct wsheader_type{
|
|
||||||
unsigned header_size;
|
|
||||||
int fin;
|
|
||||||
int mask;
|
|
||||||
enum opcode_type {
|
|
||||||
CONTINUATION = 0x0,
|
|
||||||
TEXT_FRAME = 0x1,
|
|
||||||
BINARY_FRAME = 0x2,
|
|
||||||
CLOSE = 8,
|
|
||||||
PING = 9,
|
|
||||||
PONG = 0xa,
|
|
||||||
} opcode;
|
|
||||||
int N0;
|
|
||||||
uint64_t N;
|
|
||||||
uint8_t masking_key[4];
|
|
||||||
};
|
|
||||||
|
|
||||||
struct _wsclient_context;
|
|
||||||
struct _ssl_context;
|
|
||||||
|
|
||||||
struct ssl_fun_ops{
|
|
||||||
int (*memory_set_own)( void * (*malloc_func)( size_t ),void (*free_func)( void * ) );
|
|
||||||
int (*net_connect)( int *fd, const char *host, int port );
|
|
||||||
int (*ssl_init)( struct _ssl_context *ssl );
|
|
||||||
void (*ssl_set_endpoint)( struct _ssl_context *ssl, int endpoint );
|
|
||||||
void (*ssl_set_authmode)( struct _ssl_context *ssl, int authmode );
|
|
||||||
void (*ssl_set_rng)( struct _ssl_context *ssl,
|
|
||||||
int (*f_rng)(void *, unsigned char *, size_t),
|
|
||||||
void *p_rng );
|
|
||||||
void (*ssl_set_bio)( struct _ssl_context *ssl,
|
|
||||||
int (*f_recv)(void *, unsigned char *, size_t), void *p_recv,
|
|
||||||
int (*f_send)(void *, const unsigned char *, size_t), void *p_send );
|
|
||||||
int (*ssl_handshake)( struct _ssl_context *ssl );
|
|
||||||
void (*net_close)( int fd );
|
|
||||||
void (*ssl_free)( struct _ssl_context *ssl );
|
|
||||||
int (*ssl_read)( struct _ssl_context *ssl, unsigned char *buf, size_t len );
|
|
||||||
int (*ssl_write)( struct _ssl_context *ssl, const unsigned char *buf, size_t len );
|
|
||||||
const char *(*ssl_get_ciphersuite)( const struct _ssl_context *ssl );
|
|
||||||
int (*net_recv)( void *ctx, unsigned char *buf, size_t len );
|
|
||||||
int (*net_send)( void *ctx, const unsigned char *buf, size_t len );
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ws_fun_ops{
|
|
||||||
int (*hostname_connect)(struct _wsclient_context *wsclient);
|
|
||||||
void (*client_close)(struct _wsclient_context *wsclient);
|
|
||||||
int (*client_send)(struct _wsclient_context *wsclient, unsigned char *data, size_t data_len);
|
|
||||||
int (*client_read)(struct _wsclient_context *wsclient, unsigned char *data, size_t data_len);
|
|
||||||
struct ssl_fun_ops ssl_fun_ops;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct _wsclient_context{
|
|
||||||
char host[128];
|
|
||||||
char path[128];
|
|
||||||
char origin[200];
|
|
||||||
int port;
|
|
||||||
uint8_t use_ssl;
|
|
||||||
int sockfd;
|
|
||||||
readyStateValues readyState;
|
|
||||||
int tx_len;
|
|
||||||
void *ssl;
|
|
||||||
uint8_t *txbuf;
|
|
||||||
uint8_t *rxbuf;
|
|
||||||
uint8_t *receivedData;
|
|
||||||
struct ws_fun_ops fun_ops;
|
|
||||||
}wsclient_context;
|
|
||||||
/*******************************************************************/
|
|
||||||
|
|
||||||
/****************General functions used by wsclient*****************/
|
|
||||||
void ws_get_random_bytes(void *buf, size_t len);
|
|
||||||
void* ws_malloc(unsigned int size);
|
|
||||||
void ws_free(void *buf);
|
|
||||||
int ws_client_handshake(wsclient_context *wsclient);
|
|
||||||
int ws_check_handshake(wsclient_context *wsclient);
|
|
||||||
void ws_sendData(uint8_t type, size_t message_size, uint8_t* message, int useMask, wsclient_context *wsclient);
|
|
||||||
/*******************************************************************/
|
|
||||||
|
|
||||||
/*************Functions used by wsclient without SSL****************/
|
|
||||||
|
|
||||||
int ws_hostname_connect(wsclient_context *wsclient);
|
|
||||||
int ws_client_read(wsclient_context *wsclient, unsigned char *data, size_t data_len);
|
|
||||||
int ws_client_send(wsclient_context *wsclient, unsigned char *data, size_t data_len);
|
|
||||||
void ws_client_close(wsclient_context *wsclient);
|
|
||||||
/*******************************************************************/
|
|
||||||
|
|
||||||
/***************Functions used by wsclient with SSL*****************/
|
|
||||||
int wss_hostname_connect(wsclient_context *wsclient);
|
|
||||||
int wss_client_read(wsclient_context *wsclient, unsigned char *data, size_t data_len);
|
|
||||||
int wss_client_send(wsclient_context *wsclient, unsigned char *data, size_t data_len);
|
|
||||||
void wss_client_close(wsclient_context *wsclient);
|
|
||||||
/*******************************************************************/
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,122 +0,0 @@
|
|||||||
#include "Arduino.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "lwip_netconf.h"
|
|
||||||
#include "lwip/udp.h"
|
|
||||||
#include "lwip/tcpip.h"
|
|
||||||
#include "lwip/err.h"
|
|
||||||
//#include "lwip/mem.h"
|
|
||||||
#include "lwip/tcp.h"
|
|
||||||
#include "lwip/tcp_impl.h"
|
|
||||||
#include "lwip/udp.h"
|
|
||||||
|
|
||||||
/* Get one byte from the 4-byte address */
|
|
||||||
#define ip4_addr1(ipaddr) (((u8_t*)(ipaddr))[0])
|
|
||||||
#define ip4_addr2(ipaddr) (((u8_t*)(ipaddr))[1])
|
|
||||||
#define ip4_addr3(ipaddr) (((u8_t*)(ipaddr))[2])
|
|
||||||
#define ip4_addr4(ipaddr) (((u8_t*)(ipaddr))[3])
|
|
||||||
/* These are cast to u16_t, with the intent that they are often arguments
|
|
||||||
* to printf using the U16_F format from cc.h. */
|
|
||||||
#define ip4_addr1_16(ipaddr) ((u16_t)ip4_addr1(ipaddr))
|
|
||||||
#define ip4_addr2_16(ipaddr) ((u16_t)ip4_addr2(ipaddr))
|
|
||||||
#define ip4_addr3_16(ipaddr) ((u16_t)ip4_addr3(ipaddr))
|
|
||||||
#define ip4_addr4_16(ipaddr) ((u16_t)ip4_addr4(ipaddr))
|
|
||||||
|
|
||||||
#define IP2STR(ipaddr) ip4_addr1_16(ipaddr), \
|
|
||||||
ip4_addr2_16(ipaddr), \
|
|
||||||
ip4_addr3_16(ipaddr), \
|
|
||||||
ip4_addr4_16(ipaddr)
|
|
||||||
|
|
||||||
#define IPSTR "%d.%d.%d.%d"
|
|
||||||
|
|
||||||
extern const char * const tcp_state_str[];
|
|
||||||
/*
|
|
||||||
static const char * const tcp_state_str[] = {
|
|
||||||
"CLOSED",
|
|
||||||
"LISTEN",
|
|
||||||
"SYN_SENT",
|
|
||||||
"SYN_RCVD",
|
|
||||||
"ESTABLISHED",
|
|
||||||
"FIN_WAIT_1",
|
|
||||||
"FIN_WAIT_2",
|
|
||||||
"CLOSE_WAIT",
|
|
||||||
"CLOSING",
|
|
||||||
"LAST_ACK",
|
|
||||||
"TIME_WAIT"
|
|
||||||
};
|
|
||||||
*/
|
|
||||||
/******************************************************************************
|
|
||||||
* FunctionName : debug
|
|
||||||
* Parameters :
|
|
||||||
* Returns :
|
|
||||||
*******************************************************************************/
|
|
||||||
void print_udp_pcb(void)
|
|
||||||
{
|
|
||||||
struct udp_pcb *pcb;
|
|
||||||
bool prt_none = true;
|
|
||||||
rtl_printf("UDP pcbs:\n");
|
|
||||||
for(pcb = udp_pcbs; pcb != NULL; pcb = pcb->next) {
|
|
||||||
rtl_printf("flg:%02x\t" IPSTR ":%d\t" IPSTR ":%d\trecv:%p\n", pcb->flags, IP2STR(&pcb->local_ip), pcb->local_port, IP2STR(&pcb->remote_ip), pcb->remote_port, pcb->recv );
|
|
||||||
prt_none = false;
|
|
||||||
}
|
|
||||||
if(prt_none) rtl_printf("none\n");
|
|
||||||
}
|
|
||||||
/******************************************************************************
|
|
||||||
* FunctionName : debug
|
|
||||||
* Parameters :
|
|
||||||
* Returns :
|
|
||||||
*******************************************************************************/
|
|
||||||
void print_tcp_pcb(void)
|
|
||||||
{
|
|
||||||
struct tcp_pcb *pcb;
|
|
||||||
rtl_printf("Active PCB states:\n");
|
|
||||||
bool prt_none = true;
|
|
||||||
for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {
|
|
||||||
rtl_printf("Port %d|%d\tflg:%02x\ttmr:%p\t%s\n", pcb->local_port, pcb->remote_port, pcb->flags, pcb->tmr, tcp_state_str[pcb->state]);
|
|
||||||
prt_none = false;
|
|
||||||
}
|
|
||||||
if(prt_none) rtl_printf("none\n");
|
|
||||||
rtl_printf("Listen PCB states:\n");
|
|
||||||
prt_none = true;
|
|
||||||
for(pcb = (struct tcp_pcb *)tcp_listen_pcbs.pcbs; pcb != NULL; pcb = pcb->next) {
|
|
||||||
rtl_printf("Port %d|%d\tflg:%02x\ttmr:%p\t%s\n", pcb->local_port, pcb->remote_port, pcb->flags, pcb->tmr, tcp_state_str[pcb->state]);
|
|
||||||
prt_none = false;
|
|
||||||
}
|
|
||||||
if(prt_none) rtl_printf("none\n");
|
|
||||||
rtl_printf("TIME-WAIT PCB states:\n");
|
|
||||||
prt_none = true;
|
|
||||||
for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {
|
|
||||||
rtl_printf("Port %d|%d\tflg:%02x\ttmr:%p\t%s\n", pcb->local_port, pcb->remote_port, pcb->flags, pcb->tmr, tcp_state_str[pcb->state]);
|
|
||||||
prt_none = false;
|
|
||||||
}
|
|
||||||
if(prt_none) rtl_printf("none\n");
|
|
||||||
}
|
|
||||||
/******************************************************************************
|
|
||||||
* FunctionName : debug
|
|
||||||
* Parameters :
|
|
||||||
* Returns :
|
|
||||||
*******************************************************************************/
|
|
||||||
#if 0
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
void chow_tcp_connection_info(void)
|
|
||||||
{
|
|
||||||
rtl_printf("TCP Server connections:\n");
|
|
||||||
TCP_SERV_CFG * p;
|
|
||||||
TCP_SERV_CONN * ts_conn;
|
|
||||||
bool prt_none = true;
|
|
||||||
for(p = phcfg; p != NULL; p = p->next) {
|
|
||||||
for(ts_conn = p->conn_links; ts_conn != NULL; ts_conn = ts_conn->next) {
|
|
||||||
rtl_printf("%d "IPSTR ":%d %s\n", p->port, ts_conn->remote_ip.b[0], ts_conn->remote_ip.b[1], ts_conn->remote_ip.b[2], ts_conn->remote_ip.b[3], ts_conn->remote_port, tspsrv_srvconn_state_msg(ts_conn->state) );
|
|
||||||
prt_none = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(prt_none) rtl_printf("none\n");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
@@ -18,87 +18,62 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#define ARDUINO_MAIN
|
#define ARDUINO_MAIN
|
||||||
#include "Arduino.h"
|
|
||||||
#include "cmsis_os.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#include <Arduino.h>
|
||||||
extern "C" {
|
#include <cmsis_os.h>
|
||||||
#endif // __cplusplus
|
|
||||||
|
|
||||||
#include "rtl8710b.h"
|
|
||||||
#include "FreeRTOS.h"
|
|
||||||
#include "task.h"
|
|
||||||
#include "diag.h"
|
|
||||||
extern void HalCpuClkConfig(u8 CpuType);
|
|
||||||
extern void SystemCoreClockUpdate(void);
|
|
||||||
extern void En32KCalibration(void);
|
|
||||||
extern int tcm_heap_freeSpace(void);
|
|
||||||
extern void console_init(void);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
} // extern "C"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
osThreadId main_tid = 0;
|
|
||||||
|
|
||||||
// Weak empty variant initialization function.
|
// Weak empty variant initialization function.
|
||||||
// May be redefined by variant files.
|
// May be redefined by variant files.
|
||||||
void initVariant() __attribute__((weak));
|
void initVariant() __attribute__((weak));
|
||||||
void initVariant() { }
|
|
||||||
|
void initVariant() {}
|
||||||
|
|
||||||
// Initialize C library
|
// Initialize C library
|
||||||
extern "C" void __libc_init_array(void);
|
extern "C" void __libc_init_array(void);
|
||||||
|
|
||||||
/*
|
osThreadId main_tid = 0;
|
||||||
* \brief Init Random()
|
|
||||||
* \note Use in void __low_level_init(void) { Init_Rand(); } !
|
void main_task(const void *arg) {
|
||||||
*/
|
setup();
|
||||||
void Init_Rand(void)
|
|
||||||
{
|
for (;;) {
|
||||||
extern u32 _rand_z1, _rand_z2, _rand_z3, _rand_z4, _rand_first;
|
loop();
|
||||||
u32 *p = (u32 *)0x1FFFFF00;
|
if (serialEventRun)
|
||||||
while(p < (u32 *)0x20000000) _rand_z1 ^= *p++;
|
serialEventRun();
|
||||||
_rand_z1 ^= (*((u32 *)0x40002018) << 24) ^ (*((u32 *)0x40002118) << 16) ^ (*((u32 *)0x40002218) << 8) ^ *((u32 *)0x40002318);
|
yield();
|
||||||
_rand_z2 = ((_rand_z1 & 0x007F00FF) << 7) ^ ((_rand_z1 & 0x0F80FF00) >> 8);
|
}
|
||||||
_rand_z3 = ((_rand_z2 & 0x007F00FF) << 7) ^ ((_rand_z2 & 0x0F80FF00) >> 8);
|
|
||||||
_rand_z4 = ((_rand_z3 & 0x007F00FF) << 7) ^ ((_rand_z3 & 0x0F80FF00) >> 8);
|
|
||||||
_rand_first = 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
int main(void) {
|
||||||
* \brief handle sketch
|
LT_BANNER();
|
||||||
*/
|
init();
|
||||||
void main_task( void const *arg )
|
|
||||||
{
|
|
||||||
setup();
|
|
||||||
|
|
||||||
for (;;)
|
__libc_init_array();
|
||||||
{
|
|
||||||
loop();
|
initVariant();
|
||||||
if (serialEventRun) serialEventRun();
|
|
||||||
yield();
|
osThreadDef(main_task, osPriorityRealtime, 1, 4096 * 4);
|
||||||
}
|
main_tid = osThreadCreate(osThread(main_task), NULL);
|
||||||
|
|
||||||
|
osKernelStart();
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
;
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void serialEvent() __attribute__((weak));
|
||||||
|
bool Serial_available() __attribute__((weak));
|
||||||
|
|
||||||
/*
|
void serialEventRun(void) {
|
||||||
* \brief Main entry point of Arduino application
|
if (Serial_available && serialEvent && Serial_available())
|
||||||
*/
|
serialEvent();
|
||||||
int main( void )
|
}
|
||||||
{
|
|
||||||
LT_BANNER();
|
void wait_for_debug() {
|
||||||
init();
|
while (((CoreDebug->DHCSR) & CoreDebug_DHCSR_C_DEBUGEN_Msk) == 0) {
|
||||||
|
asm("nop");
|
||||||
__libc_init_array();
|
}
|
||||||
|
delay(1000);
|
||||||
initVariant();
|
|
||||||
|
|
||||||
osThreadDef(main_task, osPriorityRealtime, 1, 4096*4);
|
|
||||||
main_tid = osThreadCreate(osThread (main_task), NULL);
|
|
||||||
|
|
||||||
osKernelStart();
|
|
||||||
|
|
||||||
while(1);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,29 +0,0 @@
|
|||||||
#ifndef __NETBIOS_H__
|
|
||||||
#define __NETBIOS_H__
|
|
||||||
|
|
||||||
/** default port number for "NetBIOS Name service */
|
|
||||||
#define NETBIOS_PORT 137
|
|
||||||
|
|
||||||
/** size of a NetBIOS name */
|
|
||||||
#define NETBIOS_NAME_LEN 16
|
|
||||||
|
|
||||||
#ifndef NET_IF_NUM
|
|
||||||
#define NET_IF_NUM 2
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
extern char netbios_name[NET_IF_NUM][NETBIOS_NAME_LEN + 1]; // default netifs/interfacenum: 0 - SoftAP, 1 - Station, 2 - Ethernet
|
|
||||||
|
|
||||||
// struct udp_pcb * netbios_pcb(void);
|
|
||||||
void netbios_init(void);
|
|
||||||
bool netbios_set_name(unsigned char interfacenum, char * name); // default netifs/interfacenum: 0 - SoftAP, 1 - Station, 2 - Ethernet
|
|
||||||
bool netbios_off(void);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* __NETBIOS_H__ */
|
|
||||||
@@ -1,88 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright (c) 2014 Arduino. All right reserved.
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
See the GNU Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <assert.h>
|
|
||||||
#include <debug.h>
|
|
||||||
#include <Arduino.h>
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif // __cplusplus
|
|
||||||
|
|
||||||
#include <diag.h>
|
|
||||||
|
|
||||||
extern void *pvPortMalloc( size_t xWantedSize );
|
|
||||||
extern size_t xPortGetFreeHeapSize( void );
|
|
||||||
extern size_t xPortGetMinimumEverFreeHeapSize( void );
|
|
||||||
|
|
||||||
extern void *tcm_heap_malloc(int size);
|
|
||||||
extern void *tcm_heap_calloc(int size);
|
|
||||||
extern void tcm_heap_free(void * mem);
|
|
||||||
extern void tcm_heap_dump(void);
|
|
||||||
extern int tcm_heap_freeSpace(void);
|
|
||||||
|
|
||||||
|
|
||||||
__attribute__((noreturn)) void __panic_func(const char* file, int line, const char* func)
|
|
||||||
{
|
|
||||||
DiagPrintf("\r\nPanic: %s, line: %d, %s\r\n");
|
|
||||||
while(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
} // extern "C"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void hexdump(void * ptr, int cnt)
|
|
||||||
{
|
|
||||||
char * p = (char *) ptr;
|
|
||||||
int c = cnt;
|
|
||||||
while(c > 64) {
|
|
||||||
DumpForOneBytes((void *)p, 64);
|
|
||||||
p += 64;
|
|
||||||
c -= 64;
|
|
||||||
}
|
|
||||||
if(c != 0) DumpForOneBytes((void *)p, c);
|
|
||||||
}
|
|
||||||
|
|
||||||
void debug_on(void)
|
|
||||||
{
|
|
||||||
ConfigDebugErr = -1;
|
|
||||||
ConfigDebugInfo = -1;
|
|
||||||
ConfigDebugWarn = -1;
|
|
||||||
CfgSysDebugErr = -1;
|
|
||||||
CfgSysDebugInfo = -1;
|
|
||||||
CfgSysDebugWarn = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void sys_info(void) {
|
|
||||||
rtl_printf("\r\nCLK CPU\t\t%d Hz\r\nRAM heap\t%d bytes\r\nTCM heap\t%d bytes\r\n",
|
|
||||||
HalGetCpuClk(), xPortGetFreeHeapSize(), tcm_heap_freeSpace());
|
|
||||||
}
|
|
||||||
|
|
||||||
void *pvPortZalloc(size_t size) {
|
|
||||||
void *pvReturn = pvPortMalloc(size);
|
|
||||||
if (pvReturn)
|
|
||||||
memset(pvReturn, 0, size);
|
|
||||||
return pvReturn;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *pvPortCalloc(size_t nmemb, size_t size) {
|
|
||||||
return pvPortZalloc(nmemb * size);
|
|
||||||
}
|
|
||||||
37
arduino/realtek-ambz/cores/arduino/sdk_extern.h
Normal file
37
arduino/realtek-ambz/cores/arduino/sdk_extern.h
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
/* Copyright (c) Kuba Szczodrzyński 2022-05-06. */
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#define boolean boolean_rtl
|
||||||
|
#include <ameba_soc.h>
|
||||||
|
#include <gpio_api.h>
|
||||||
|
#include <rand.h>
|
||||||
|
#include <rt_lib_rom.h>
|
||||||
|
#include <rtl_lib.h>
|
||||||
|
#include <wait_api.h>
|
||||||
|
#undef boolean
|
||||||
|
|
||||||
|
// stdio.h
|
||||||
|
#define printf rtl_printf
|
||||||
|
#define sprintf rtl_sprintf
|
||||||
|
|
||||||
|
// moved from syscalls.h
|
||||||
|
#define _close __rtl_close
|
||||||
|
#define _fstat __rtl_fstat
|
||||||
|
#define _isatty __rtl_isatty
|
||||||
|
#define _lseek __rtl_lseek
|
||||||
|
#define _open __rtl_open
|
||||||
|
#define _read __rtl_read
|
||||||
|
#define _write __rtl_write
|
||||||
|
#define _sbrk __rtl_sbrk
|
||||||
|
|
||||||
|
#define delay_us wait_us
|
||||||
|
|
||||||
|
extern void wait_us(int us);
|
||||||
|
extern int LOGUART_SetBaud(uint32_t BaudRate); // from fixups/log_uart.c
|
||||||
|
extern void DumpForOneBytes(void *addr, int cnt); // cnt max 0x70!
|
||||||
|
extern void SystemCoreClockUpdate(void);
|
||||||
16
arduino/realtek-ambz/cores/arduino/sdk_mem.c
Normal file
16
arduino/realtek-ambz/cores/arduino/sdk_mem.c
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
/* Copyright (c) Kuba Szczodrzyński 2022-05-06. */
|
||||||
|
|
||||||
|
#include "sdk_mem.h"
|
||||||
|
|
||||||
|
#include <Arduino.h> // for memset
|
||||||
|
|
||||||
|
void *pvPortZalloc(size_t size) {
|
||||||
|
void *pvReturn = pvPortMalloc(size);
|
||||||
|
if (pvReturn)
|
||||||
|
memset(pvReturn, 0, size);
|
||||||
|
return pvReturn;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *pvPortCalloc(size_t nmemb, size_t size) {
|
||||||
|
return pvPortZalloc(nmemb * size);
|
||||||
|
}
|
||||||
19
arduino/realtek-ambz/cores/arduino/sdk_mem.h
Normal file
19
arduino/realtek-ambz/cores/arduino/sdk_mem.h
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
/* Copyright (c) Kuba Szczodrzyński 2022-05-06. */
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
// provide extern functions directly, as callers
|
||||||
|
// generally don't expect needing to include malloc()
|
||||||
|
extern void *pvPortMalloc(size_t xWantedSize);
|
||||||
|
extern void *pvPortZalloc(size_t size);
|
||||||
|
extern void *pvPortCalloc(size_t nmemb, size_t size);
|
||||||
|
extern void *pvPortReAlloc(void *pv, size_t xWantedSize);
|
||||||
|
extern void vPortFree(void *pv);
|
||||||
|
|
||||||
|
#define malloc pvPortMalloc
|
||||||
|
#define zalloc pvPortZalloc
|
||||||
|
#define calloc pvPortCalloc
|
||||||
|
#define realloc pvPortReAlloc
|
||||||
|
#define free vPortFree
|
||||||
110
arduino/realtek-ambz/cores/arduino/sdk_os.c
Normal file
110
arduino/realtek-ambz/cores/arduino/sdk_os.c
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
#include "sdk_os.h"
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <cmsis_os.h>
|
||||||
|
|
||||||
|
uint32_t os_thread_create(void (*task)(const void *argument), void *argument, int priority, uint32_t stack_size) {
|
||||||
|
|
||||||
|
osThreadDef_t thread_def;
|
||||||
|
|
||||||
|
thread_def.pthread = task;
|
||||||
|
thread_def.tpriority = (osPriority)priority;
|
||||||
|
// the underlying freertos implementation on cmsis os divide stack size by 4
|
||||||
|
thread_def.stacksize = stack_size * 4;
|
||||||
|
thread_def.name = "ARDUINO";
|
||||||
|
|
||||||
|
return (uint32_t)osThreadCreate(&thread_def, argument);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t os_thread_get_id(void) {
|
||||||
|
return osThreadGetId();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t os_thread_terminate(uint32_t thread_id) {
|
||||||
|
return (uint32_t)osThreadTerminate(thread_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t os_thread_yield(void) {
|
||||||
|
return (uint32_t)osThreadYield();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t os_thread_set_priority(uint32_t thread_id, int priority) {
|
||||||
|
return (uint32_t)osThreadSetPriority(thread_id, (osPriority)priority);
|
||||||
|
}
|
||||||
|
|
||||||
|
int os_thread_get_priority(uint32_t thread_id) {
|
||||||
|
return (int)osThreadGetPriority(thread_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t os_signal_set(uint32_t thread_id, int32_t signals) {
|
||||||
|
return osSignalSet(thread_id, signals);
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t os_signal_clear(uint32_t thread_id, int32_t signals) {
|
||||||
|
return osSignalClear(thread_id, signals);
|
||||||
|
}
|
||||||
|
|
||||||
|
os_event_t os_signal_wait(int32_t signals, uint32_t millisec) {
|
||||||
|
|
||||||
|
osEvent evt;
|
||||||
|
os_event_t ret;
|
||||||
|
|
||||||
|
evt = osSignalWait(signals, millisec);
|
||||||
|
ret.status = (uint32_t)evt.status;
|
||||||
|
ret.value.signals = evt.value.signals;
|
||||||
|
ret.def.message_id = evt.def.message_id;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef void (*os_ptimer)(const void *argument);
|
||||||
|
|
||||||
|
uint32_t os_timer_create(void (*callback)(const void *argument), uint8_t isPeriodic, void *argument) {
|
||||||
|
|
||||||
|
osTimerDef_t *pTimerDef;
|
||||||
|
|
||||||
|
pTimerDef = (osTimerDef_t *)malloc(sizeof(osTimerDef_t));
|
||||||
|
pTimerDef->ptimer = callback;
|
||||||
|
pTimerDef->custom = (struct os_timer_custom *)malloc(sizeof(struct os_timer_custom));
|
||||||
|
|
||||||
|
return osTimerCreate(pTimerDef, (isPeriodic ? osTimerPeriodic : osTimerOnce), argument);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t os_timer_start(uint32_t timer_id, uint32_t millisec) {
|
||||||
|
return osTimerStart(timer_id, millisec);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t os_timer_stop(uint32_t timer_id) {
|
||||||
|
return osTimerStop(timer_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t os_timer_delete(uint32_t timer_id) {
|
||||||
|
|
||||||
|
osTimerDef_t *pTimerDef;
|
||||||
|
|
||||||
|
pTimerDef = (osTimerDef_t *)pvTimerGetTimerID(timer_id);
|
||||||
|
free(pTimerDef->custom);
|
||||||
|
free(pTimerDef);
|
||||||
|
|
||||||
|
return osTimerDelete(timer_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t os_semaphore_create(int32_t count) {
|
||||||
|
return (uint32_t)osSemaphoreCreate(NULL, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t os_semaphore_wait(uint32_t semaphore_id, uint32_t millisec) {
|
||||||
|
if (osSemaphoreWait((osSemaphoreId)semaphore_id, millisec) == 0) {
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t os_semaphore_release(uint32_t semaphore_id) {
|
||||||
|
return (uint32_t)osSemaphoreRelease((osSemaphoreId)semaphore_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t os_semaphore_delete(uint32_t semaphore_id) {
|
||||||
|
return (uint32_t)osSemaphoreDelete((osSemaphoreId)semaphore_id);
|
||||||
|
}
|
||||||
@@ -1,13 +1,4 @@
|
|||||||
/** @file wiring_os.h */
|
#pragma once
|
||||||
|
|
||||||
/**
|
|
||||||
* @defgroup wiring_os wiring_os
|
|
||||||
* OS realted function for thread, signal, software timer, semaphore
|
|
||||||
* @{
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _WIRING_OS_H_
|
|
||||||
#define _WIRING_OS_H_
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@@ -21,33 +12,33 @@ extern "C" {
|
|||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
/** function completed; no error or event occurred. */
|
/** function completed; no error or event occurred. */
|
||||||
#define OS_OK 0x00
|
#define OS_OK 0x00
|
||||||
/** function completed; signal event occurred. */
|
/** function completed; signal event occurred. */
|
||||||
#define OS_EVENT_SIGNAL 0x08
|
#define OS_EVENT_SIGNAL 0x08
|
||||||
/** function completed; message event occurred. */
|
/** function completed; message event occurred. */
|
||||||
#define OS_EVENT_MESSAGE 0x10
|
#define OS_EVENT_MESSAGE 0x10
|
||||||
/** function completed; mail event occurred. */
|
/** function completed; mail event occurred. */
|
||||||
#define OS_EVENT_MAIL 0x20
|
#define OS_EVENT_MAIL 0x20
|
||||||
/** function completed; timeout occurred. */
|
/** function completed; timeout occurred. */
|
||||||
#define OS_EVENT_TIMEOUT 0x40
|
#define OS_EVENT_TIMEOUT 0x40
|
||||||
/** parameter error: a mandatory parameter was missing or specified an incorrect object. */
|
/** parameter error: a mandatory parameter was missing or specified an incorrect object. */
|
||||||
#define OS_ERROR_PARAMETER 0x80
|
#define OS_ERROR_PARAMETER 0x80
|
||||||
/** resource not available: a specified resource was not available. */
|
/** resource not available: a specified resource was not available. */
|
||||||
#define OS_ERROR_RESOURCE 0x81
|
#define OS_ERROR_RESOURCE 0x81
|
||||||
/** resource not available within given time: a specified resource was not available within the timeout period. */
|
/** resource not available within given time: a specified resource was not available within the timeout period. */
|
||||||
#define OS_ERROR_TIMEOUT_RESOURCE 0xC1
|
#define OS_ERROR_TIMEOUT_RESOURCE 0xC1
|
||||||
/** not allowed in ISR context: the function cannot be called from interrupt service routines. */
|
/** not allowed in ISR context: the function cannot be called from interrupt service routines. */
|
||||||
#define OS_ERROR_ISR 0x82
|
#define OS_ERROR_ISR 0x82
|
||||||
/** function called multiple times from ISR with same object. */
|
/** function called multiple times from ISR with same object. */
|
||||||
#define OS_ERROR_ISR_RECURSIVE 0x83
|
#define OS_ERROR_ISR_RECURSIVE 0x83
|
||||||
/** system cannot determine priority or thread has illegal priority. */
|
/** system cannot determine priority or thread has illegal priority. */
|
||||||
#define OS_ERROR_PRIORITY 0x84
|
#define OS_ERROR_PRIORITY 0x84
|
||||||
/** system is out of memory: it was impossible to allocate or reserve memory for the operation. */
|
/** system is out of memory: it was impossible to allocate or reserve memory for the operation. */
|
||||||
#define OS_ERROR_NO_MEMORY 0x85
|
#define OS_ERROR_NO_MEMORY 0x85
|
||||||
/** value of a parameter is out of range. */
|
/** value of a parameter is out of range. */
|
||||||
#define OS_ERROR_VALUE 0x86
|
#define OS_ERROR_VALUE 0x86
|
||||||
/** unspecified RTOS error: run-time error but no other error message fits. */
|
/** unspecified RTOS error: run-time error but no other error message fits. */
|
||||||
#define OS_ERROR_OS 0xFF
|
#define OS_ERROR_OS 0xFF
|
||||||
/** @} */ // end of group os_status
|
/** @} */ // end of group os_status
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -56,19 +47,19 @@ extern "C" {
|
|||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
/** priority: idle (lowest) */
|
/** priority: idle (lowest) */
|
||||||
#define OS_PRIORITY_IDLE (-3)
|
#define OS_PRIORITY_IDLE (-3)
|
||||||
/** priority: low */
|
/** priority: low */
|
||||||
#define OS_PRIORITY_LOW (-2)
|
#define OS_PRIORITY_LOW (-2)
|
||||||
/** priority: below normal */
|
/** priority: below normal */
|
||||||
#define OS_PRIORITY_BELOW_NORMAL (-1)
|
#define OS_PRIORITY_BELOW_NORMAL (-1)
|
||||||
/** priority: normal (default) */
|
/** priority: normal (default) */
|
||||||
#define OS_PRIORITY_NORMAL ( 0)
|
#define OS_PRIORITY_NORMAL (0)
|
||||||
/** priority: above normal */
|
/** priority: above normal */
|
||||||
#define OS_PRIORITY_ABOVENORMAL (+1)
|
#define OS_PRIORITY_ABOVENORMAL (+1)
|
||||||
/** priority: high */
|
/** priority: high */
|
||||||
#define OS_PRIORITY_HIGH (+2)
|
#define OS_PRIORITY_HIGH (+2)
|
||||||
/** priority: realtime (highest) */
|
/** priority: realtime (highest) */
|
||||||
#define OS_PRIORITY_REALTIME (+3)
|
#define OS_PRIORITY_REALTIME (+3)
|
||||||
/** @} */ // end of group os_priority
|
/** @} */ // end of group os_priority
|
||||||
|
|
||||||
#ifndef DEFAULT_STACK_SIZE
|
#ifndef DEFAULT_STACK_SIZE
|
||||||
@@ -87,16 +78,18 @@ extern "C" {
|
|||||||
* Redefine osEvent in cmsis_os.h
|
* Redefine osEvent in cmsis_os.h
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint32_t status; ///< status code: event or error information
|
uint32_t status; ///< status code: event or error information
|
||||||
union {
|
|
||||||
uint32_t v; ///< message as 32-bit value
|
union {
|
||||||
void *p; ///< message or mail as void pointer
|
uint32_t v; ///< message as 32-bit value
|
||||||
int32_t signals; ///< signal flags
|
void *p; ///< message or mail as void pointer
|
||||||
} value; ///< event value
|
int32_t signals; ///< signal flags
|
||||||
union {
|
} value; ///< event value
|
||||||
void *mail_id; ///< mail id obtained by osMailCreate
|
|
||||||
void *message_id; ///< message id obtained by osMessageCreate
|
union {
|
||||||
} def; ///< event definition
|
void *mail_id; ///< mail id obtained by osMailCreate
|
||||||
|
void *message_id; ///< message id obtained by osMessageCreate
|
||||||
|
} def; ///< event definition
|
||||||
} os_event_t;
|
} os_event_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -108,12 +101,14 @@ typedef struct {
|
|||||||
* @ingroup thread_management
|
* @ingroup thread_management
|
||||||
* @brief Create a thread and add it to Active Threads and set it to state READY.
|
* @brief Create a thread and add it to Active Threads and set it to state READY.
|
||||||
*
|
*
|
||||||
* @param[in] task Function pointer which is the thread body. It should not run into the end of function unless os_thread_terminate is invoked
|
* @param[in] task Function pointer which is the thread body. It should not run into the end of function unless
|
||||||
|
* os_thread_terminate is invoked
|
||||||
* @param[in] argument the data pointer which brings to task
|
* @param[in] argument the data pointer which brings to task
|
||||||
* @param[in] priority The underlying os is FreeRTOS. It executes tasks with highest priority which are not in idle state.\n
|
* @param[in] priority The underlying os is FreeRTOS. It executes tasks with highest priority which are not in idle
|
||||||
* If there are more than 2 tasks to be executed, then they share the time slice.
|
* state.\n If there are more than 2 tasks to be executed, then they share the time slice.
|
||||||
* @param[in] stack_size The stack_size is used as memory heap only for this task. \n
|
* @param[in] stack_size The stack_size is used as memory heap only for this task. \n
|
||||||
* The local variables and call stacks would occupy this heap. Please make sure the the stack_size is big enough to avoid curroption
|
* The local variables and call stacks would occupy this heap. Please make sure the the stack_size is big enough to
|
||||||
|
* avoid curroption
|
||||||
* @return The thread id which is used in thread operation and signaling.
|
* @return The thread id which is used in thread operation and signaling.
|
||||||
*/
|
*/
|
||||||
extern uint32_t os_thread_create(void (*task)(const void *argument), void *argument, int priority, uint32_t stack_size);
|
extern uint32_t os_thread_create(void (*task)(const void *argument), void *argument, int priority, uint32_t stack_size);
|
||||||
@@ -124,7 +119,7 @@ extern uint32_t os_thread_create(void (*task)(const void *argument), void *argum
|
|||||||
*
|
*
|
||||||
* @return Current thread id which calls os_thread_get_id
|
* @return Current thread id which calls os_thread_get_id
|
||||||
*/
|
*/
|
||||||
extern uint32_t os_thread_get_id( void );
|
extern uint32_t os_thread_get_id(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ingroup thread_management
|
* @ingroup thread_management
|
||||||
@@ -141,9 +136,10 @@ extern uint32_t os_thread_terminate(uint32_t thread_id);
|
|||||||
* @ingroup thread_management
|
* @ingroup thread_management
|
||||||
* @brief Pass control to next thread that is in state \b READY.
|
* @brief Pass control to next thread that is in state \b READY.
|
||||||
*
|
*
|
||||||
* By default the minimal execution unit is 1 millisecond. In a scenario that if a thread with smaller want to handout execution right to a thread with
|
* By default the minimal execution unit is 1 millisecond. In a scenario that if a thread with smaller want to handout
|
||||||
* higher priority immediately without waiting for the ending of current 1 millisecond, then invoke os_thread_yield can transfer exection right to
|
* execution right to a thread with higher priority immediately without waiting for the ending of current 1 millisecond,
|
||||||
* OS's idle task and check which is the next execution thread.
|
* then invoke os_thread_yield can transfer exection right to OS's idle task and check which is the next execution
|
||||||
|
* thread.
|
||||||
*
|
*
|
||||||
* @return os_status code
|
* @return os_status code
|
||||||
*/
|
*/
|
||||||
@@ -168,7 +164,7 @@ extern uint32_t os_thread_set_priority(uint32_t thread_id, int priority);
|
|||||||
*/
|
*/
|
||||||
extern int os_thread_get_priority(uint32_t thread_id);
|
extern int os_thread_get_priority(uint32_t thread_id);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @defgroup signal_management signal_management
|
* @defgroup signal_management signal_management
|
||||||
* Signaling between threads include set, clear, and wait
|
* Signaling between threads include set, clear, and wait
|
||||||
*/
|
*/
|
||||||
@@ -196,7 +192,7 @@ extern int32_t os_signal_clear(uint32_t thread_id, int32_t signals);
|
|||||||
/**
|
/**
|
||||||
* @ingroup signal_management
|
* @ingroup signal_management
|
||||||
* @brief Wait for one or more Signal Flags to become signaled for the current \b RUNNING thread.
|
* @brief Wait for one or more Signal Flags to become signaled for the current \b RUNNING thread.
|
||||||
*
|
*
|
||||||
* @param[in] signals the signals to be wait
|
* @param[in] signals the signals to be wait
|
||||||
* @param[in] millisec the timeout value if no signal comes in. Fill in 0xFFFFFFFF for infinite wait.
|
* @param[in] millisec the timeout value if no signal comes in. Fill in 0xFFFFFFFF for infinite wait.
|
||||||
* @return os_status code
|
* @return os_status code
|
||||||
@@ -208,14 +204,14 @@ extern os_event_t os_signal_wait(int32_t signals, uint32_t millisec);
|
|||||||
* Software timer management include create, start, stop, delete.
|
* Software timer management include create, start, stop, delete.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ingroup timer_management
|
* @ingroup timer_management
|
||||||
* @brief specify timer type that invoke only once
|
* @brief specify timer type that invoke only once
|
||||||
*/
|
*/
|
||||||
#define OS_TIMER_ONCE (0)
|
#define OS_TIMER_ONCE (0)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ingroup timer_management
|
* @ingroup timer_management
|
||||||
* @brief specify timer type that invoke periodically
|
* @brief specify timer type that invoke periodically
|
||||||
*/
|
*/
|
||||||
#define OS_TIMER_PERIODIC (1)
|
#define OS_TIMER_PERIODIC (1)
|
||||||
@@ -229,7 +225,7 @@ extern os_event_t os_signal_wait(int32_t signals, uint32_t millisec);
|
|||||||
* @param[in] argument The argument that is bring into callback function
|
* @param[in] argument The argument that is bring into callback function
|
||||||
* @return timer id
|
* @return timer id
|
||||||
*/
|
*/
|
||||||
extern uint32_t os_timer_create(void (*callback)(void const *argument), uint8_t isPeriodic, void *argument);
|
extern uint32_t os_timer_create(void (*callback)(const void *argument), uint8_t isPeriodic, void *argument);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ingroup timer_management
|
* @ingroup timer_management
|
||||||
@@ -239,7 +235,7 @@ extern uint32_t os_timer_create(void (*callback)(void const *argument), uint8_t
|
|||||||
* @param[in] millisec The delays after timer starts
|
* @param[in] millisec The delays after timer starts
|
||||||
* @return os_status code
|
* @return os_status code
|
||||||
*/
|
*/
|
||||||
extern uint32_t os_timer_start (uint32_t timer_id, uint32_t millisec);
|
extern uint32_t os_timer_start(uint32_t timer_id, uint32_t millisec);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ingroup timer_management
|
* @ingroup timer_management
|
||||||
@@ -248,7 +244,7 @@ extern uint32_t os_timer_start (uint32_t timer_id, uint32_t millisec);
|
|||||||
* @param[in] timer_id The timer id obtained from by os_timer_create
|
* @param[in] timer_id The timer id obtained from by os_timer_create
|
||||||
* @return os_status code
|
* @return os_status code
|
||||||
*/
|
*/
|
||||||
extern uint32_t os_timer_stop (uint32_t timer_id);
|
extern uint32_t os_timer_stop(uint32_t timer_id);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ingroup timer_management
|
* @ingroup timer_management
|
||||||
@@ -304,7 +300,3 @@ extern uint32_t os_semaphore_delete(uint32_t semaphore_id);
|
|||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/** @} */ // end of group wiring_os
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
The MIT License (MIT)
|
|
||||||
|
|
||||||
Copyright (c) 2013-2015 Peter Andersson (pelleplutt1976<at>gmail.com)
|
|
||||||
|
|
||||||
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.
|
|
||||||
@@ -1,146 +0,0 @@
|
|||||||
# SPIFFS (SPI Flash File System)
|
|
||||||
**V0.3.4**
|
|
||||||
|
|
||||||
Copyright (c) 2013-2016 Peter Andersson (pelleplutt1976 at gmail.com)
|
|
||||||
|
|
||||||
For legal stuff, see [LICENSE](https://github.com/pellepl/spiffs/blob/master/LICENSE). Basically, you may do whatever you want with the source. Use, modify, sell, print it out, roll it and smoke it - as long as I won't be held responsible.
|
|
||||||
|
|
||||||
Love to hear feedback though!
|
|
||||||
|
|
||||||
|
|
||||||
## INTRODUCTION
|
|
||||||
|
|
||||||
Spiffs is a file system intended for SPI NOR flash devices on embedded targets.
|
|
||||||
|
|
||||||
Spiffs is designed with following characteristics in mind:
|
|
||||||
- Small (embedded) targets, sparse RAM without heap
|
|
||||||
- Only big areas of data (blocks) can be erased
|
|
||||||
- An erase will reset all bits in block to ones
|
|
||||||
- Writing pulls one to zeroes
|
|
||||||
- Zeroes can only be pulled to ones by erase
|
|
||||||
- Wear leveling
|
|
||||||
|
|
||||||
|
|
||||||
## FEATURES
|
|
||||||
|
|
||||||
What spiffs does:
|
|
||||||
- Specifically designed for low ram usage
|
|
||||||
- Uses statically sized ram buffers, independent of number of files
|
|
||||||
- Posix-like api: open, close, read, write, seek, stat, etc
|
|
||||||
- It can be run on any NOR flash, not only SPI flash - theoretically also on embedded flash of an microprocessor
|
|
||||||
- Multiple spiffs configurations can be run on same target - and even on same SPI flash device
|
|
||||||
- Implements static wear leveling
|
|
||||||
- Built in file system consistency checks
|
|
||||||
|
|
||||||
What spiffs does not:
|
|
||||||
- Presently, spiffs does not support directories. It produces a flat structure. Creating a file with path *tmp/myfile.txt* will create a file called *tmp/myfile.txt* instead of a *myfile.txt* under directory *tmp*.
|
|
||||||
- It is not a realtime stack. One write operation might take much longer than another.
|
|
||||||
- Poor scalability. Spiffs is intended for small memory devices - the normal sizes for SPI flashes. Going beyond ~128MB is probably a bad idea. This is a side effect of the design goal to use as little ram as possible.
|
|
||||||
- Presently, it does not detect or handle bad blocks.
|
|
||||||
|
|
||||||
|
|
||||||
## MORE INFO
|
|
||||||
|
|
||||||
See the [wiki](https://github.com/pellepl/spiffs/wiki) for configuring, integrating and using spiffs.
|
|
||||||
|
|
||||||
For design, see [docs/TECH_SPEC](https://github.com/pellepl/spiffs/blob/master/docs/TECH_SPEC).
|
|
||||||
|
|
||||||
For a generic spi flash driver, see [this](https://github.com/pellepl/spiflash_driver).
|
|
||||||
|
|
||||||
## HISTORY
|
|
||||||
|
|
||||||
### 0.3.4
|
|
||||||
- Added user callback file func.
|
|
||||||
- Fixed a stat bug with obj id.
|
|
||||||
- SPIFFS_probe_fs added
|
|
||||||
- Add possibility to compile a read-only version of spiffs
|
|
||||||
- Make magic dependent on fs length, if needed (see #59 & #66) (thanks @hreintke)
|
|
||||||
- Exposed SPIFFS_open_by_page_function
|
|
||||||
- Zero-size file cannot be seek #57 (thanks @lishen2)
|
|
||||||
- Add tell and eof functions #54 (thanks @raburton)
|
|
||||||
- Make api string params const #53 (thanks @raburton)
|
|
||||||
- Preserve user_data during mount() #51 (thanks @rojer)
|
|
||||||
|
|
||||||
New API functions:
|
|
||||||
- `SPIFFS_set_file_callback_func` - register a callback informing about file events
|
|
||||||
- `SPIFFS_probe_fs` - probe a spi flash trying to figure out size of fs
|
|
||||||
- `SPIFFS_open_by_page` - open a file by page index
|
|
||||||
- `SPIFFS_eof` - checks if end of file is reached
|
|
||||||
- `SPIFFS_tell` - returns current file offset
|
|
||||||
|
|
||||||
New config defines:
|
|
||||||
- `SPIFFS_READ_ONLY`
|
|
||||||
- `SPIFFS_USE_MAGIC_LENGTH`
|
|
||||||
|
|
||||||
### 0.3.3
|
|
||||||
**Might not be compatible with 0.3.2 structures. See issue #40**
|
|
||||||
- Possibility to add integer offset to file handles
|
|
||||||
- Truncate function presumes too few free pages #49
|
|
||||||
- Bug in truncate function #48 (thanks @PawelDefee)
|
|
||||||
- Update spiffs_gc.c - remove unnecessary parameter (thanks @PawelDefee)
|
|
||||||
- Update INTEGRATION docs (thanks @PawelDefee)
|
|
||||||
- Fix pointer truncation in 64-bit platforms (thanks @igrr)
|
|
||||||
- Zero-sized files cannot be read #44 (thanks @rojer)
|
|
||||||
- (More) correct calculation of max_id in obj_lu_find #42 #41 (thanks @lishen2)
|
|
||||||
- Check correct error code in obj_lu_find_free #41 (thanks @lishen2)
|
|
||||||
- Moar comments for SPIFFS_lseek (thanks @igrr)
|
|
||||||
- Fixed padding in spiffs_page_object_ix #40 (thanks @jmattsson @lishen2)
|
|
||||||
- Fixed gc_quick test (thanks @jmattsson)
|
|
||||||
- Add SPIFFS_EXCL flag #36
|
|
||||||
- SPIFFS_close may fail silently if cache is enabled #37
|
|
||||||
- User data in callbacks #34
|
|
||||||
- Ignoring SINGLETON build in cache setup (thanks Luca)
|
|
||||||
- Compilation error fixed #32 (thanks @chotasanjiv)
|
|
||||||
- Align cand_scores (thanks @hefloryd)
|
|
||||||
- Fix build warnings when SPIFFS_CACHE is 0 (thanks @ajaybhargav)
|
|
||||||
|
|
||||||
New config defines:
|
|
||||||
- `SPIFFS_FILEHDL_OFFSET`
|
|
||||||
|
|
||||||
### 0.3.2
|
|
||||||
- Limit cache size if too much cache is given (thanks pgeiem)
|
|
||||||
- New feature - Controlled erase. #23
|
|
||||||
- SPIFFS_rename leaks file descriptors #28 (thanks benpicco)
|
|
||||||
- moved dbg print defines in test framework to params_test.h
|
|
||||||
- lseek should return the resulting offset (thanks hefloryd)
|
|
||||||
- fixed type on dbg ifdefs
|
|
||||||
- silence warning about signed/unsigned comparison when spiffs_obj_id is 32 bit (thanks benpicco)
|
|
||||||
- Possible error in test_spiffs.c #21 (thanks yihcdaso-yeskela)
|
|
||||||
- Cache might writethrough too often #16
|
|
||||||
- even moar testrunner updates
|
|
||||||
- Test framework update and some added tests
|
|
||||||
- Some thoughts for next gen
|
|
||||||
- Test sigsevs when having too many sectors #13 (thanks alonewolfx2)
|
|
||||||
- GC might be suboptimal #11
|
|
||||||
- Fix eternal readdir when objheader at last block, last entry
|
|
||||||
|
|
||||||
New API functions:
|
|
||||||
- `SPIFFS_gc_quick` - call a nonintrusive gc
|
|
||||||
- `SPIFFS_gc` - call a full-scale intrusive gc
|
|
||||||
|
|
||||||
### 0.3.1
|
|
||||||
- Removed two return warnings, was too triggerhappy on release
|
|
||||||
|
|
||||||
### 0.3.0
|
|
||||||
- Added existing namecheck when creating files
|
|
||||||
- Lots of static analysis bugs #6
|
|
||||||
- Added rename func
|
|
||||||
- Fix SPIFFS_read length when reading beyond file size
|
|
||||||
- Added reading beyond file length testcase
|
|
||||||
- Made build a bit more configurable
|
|
||||||
- Changed name in spiffs from "errno" to "err_code" due to conflicts compiling in mingw
|
|
||||||
- Improved GC checks, fixed an append bug, more robust truncate for very special case
|
|
||||||
- GC checks preempts GC, truncate even less picky
|
|
||||||
- Struct alignment needed for some targets, define in spiffs config #10
|
|
||||||
- Spiffs filesystem magic, definable in config
|
|
||||||
|
|
||||||
New config defines:
|
|
||||||
- `SPIFFS_USE_MAGIC` - enable or disable magic check upon mount
|
|
||||||
- `SPIFFS_ALIGNED_OBJECT_INDEX_TABLES` - alignment for certain targets
|
|
||||||
|
|
||||||
New API functions:
|
|
||||||
- `SPIFFS_rename` - rename files
|
|
||||||
- `SPIFFS_clearerr` - clears last errno
|
|
||||||
- `SPIFFS_info` - returns info on used and total bytes in fs
|
|
||||||
- `SPIFFS_format` - formats the filesystem
|
|
||||||
- `SPIFFS_mounted` - checks if filesystem is mounted
|
|
||||||
@@ -1,239 +0,0 @@
|
|||||||
* USING SPIFFS
|
|
||||||
|
|
||||||
TODO
|
|
||||||
|
|
||||||
|
|
||||||
* SPIFFS DESIGN
|
|
||||||
|
|
||||||
Spiffs is inspired by YAFFS. However, YAFFS is designed for NAND flashes, and
|
|
||||||
for bigger targets with much more ram. Nevertheless, many wise thoughts have
|
|
||||||
been borrowed from YAFFS when writing spiffs. Kudos!
|
|
||||||
|
|
||||||
The main complication writing spiffs was that it cannot be assumed the target
|
|
||||||
has a heap. Spiffs must go along only with the work ram buffer given to it.
|
|
||||||
This forces extra implementation on many areas of spiffs.
|
|
||||||
|
|
||||||
|
|
||||||
** SPI flash devices using NOR technology
|
|
||||||
|
|
||||||
Below is a small description of how SPI flashes work internally. This is to
|
|
||||||
give an understanding of the design choices made in spiffs.
|
|
||||||
|
|
||||||
SPI flash devices are physically divided in blocks. On some SPI flash devices,
|
|
||||||
blocks are further divided into sectors. Datasheets sometimes name blocks as
|
|
||||||
sectors and vice versa.
|
|
||||||
|
|
||||||
Common memory capacaties for SPI flashes are 512kB up to 8MB of data, where
|
|
||||||
blocks may be 64kB. Sectors can be e.g. 4kB, if supported. Many SPI flashes
|
|
||||||
have uniform block sizes, whereas others have non-uniform - the latter meaning
|
|
||||||
that e.g. the first 16 blocks are 4kB big, and the rest are 64kB.
|
|
||||||
|
|
||||||
The entire memory is linear and can be read and written in random access.
|
|
||||||
Erasing can only be done block- or sectorwise; or by mass erase.
|
|
||||||
|
|
||||||
SPI flashes can normally be erased from 100.000 up to 1.000.000 cycles before
|
|
||||||
they fail.
|
|
||||||
|
|
||||||
A clean SPI flash from factory have all bits in entire memory set to one. A
|
|
||||||
mass erase will reset the device to this state. Block or sector erasing will
|
|
||||||
put the all bits in the area given by the sector or block to ones. Writing to a
|
|
||||||
NOR flash pulls ones to zeroes. Writing 0xFF to an address is simply a no-op.
|
|
||||||
|
|
||||||
Writing 0b10101010 to a flash address holding 0b00001111 will yield 0b00001010.
|
|
||||||
|
|
||||||
This way of "write by nand" is used considerably in spiffs.
|
|
||||||
|
|
||||||
Common characteristics of NOR flashes are quick reads, but slow writes.
|
|
||||||
|
|
||||||
And finally, unlike NAND flashes, NOR flashes seem to not need any error
|
|
||||||
correction. They always write correctly I gather.
|
|
||||||
|
|
||||||
|
|
||||||
** Spiffs logical structure
|
|
||||||
|
|
||||||
Some terminology before proceeding. Physical blocks/sectors means sizes stated
|
|
||||||
in the datasheet. Logical blocks and pages is something the integrator choose.
|
|
||||||
|
|
||||||
|
|
||||||
** Blocks and pages
|
|
||||||
|
|
||||||
Spiffs is allocated to a part or all of the memory of the SPI flash device.
|
|
||||||
This area is divided into logical blocks, which in turn are divided into
|
|
||||||
logical pages. The boundary of a logical block must coincide with one or more
|
|
||||||
physical blocks. The sizes for logical blocks and logical pages always remain
|
|
||||||
the same, they are uniform.
|
|
||||||
|
|
||||||
Example: non-uniform flash mapped to spiffs with 128kB logical blocks
|
|
||||||
|
|
||||||
PHYSICAL FLASH BLOCKS SPIFFS LOGICAL BLOCKS: 128kB
|
|
||||||
|
|
||||||
+-----------------------+ - - - +-----------------------+
|
|
||||||
| Block 1 : 16kB | | Block 1 : 128kB |
|
|
||||||
+-----------------------+ | |
|
|
||||||
| Block 2 : 16kB | | |
|
|
||||||
+-----------------------+ | |
|
|
||||||
| Block 3 : 16kB | | |
|
|
||||||
+-----------------------+ | |
|
|
||||||
| Block 4 : 16kB | | |
|
|
||||||
+-----------------------+ | |
|
|
||||||
| Block 5 : 64kB | | |
|
|
||||||
+-----------------------+ - - - +-----------------------+
|
|
||||||
| Block 6 : 64kB | | Block 2 : 128kB |
|
|
||||||
+-----------------------+ | |
|
|
||||||
| Block 7 : 64kB | | |
|
|
||||||
+-----------------------+ - - - +-----------------------+
|
|
||||||
| Block 8 : 64kB | | Block 3 : 128kB |
|
|
||||||
+-----------------------+ | |
|
|
||||||
| Block 9 : 64kB | | |
|
|
||||||
+-----------------------+ - - - +-----------------------+
|
|
||||||
| ... | | ... |
|
|
||||||
|
|
||||||
A logical block is divided further into a number of logical pages. A page
|
|
||||||
defines the smallest data holding element known to spiffs. Hence, if a file
|
|
||||||
is created being one byte big, it will occupy one page for index and one page
|
|
||||||
for data - it will occupy 2 x size of a logical page on flash.
|
|
||||||
So it seems it is good to select a small page size.
|
|
||||||
|
|
||||||
Each page has a metadata header being normally 5 to 9 bytes. This said, a very
|
|
||||||
small page size will make metadata occupy a lot of the memory on the flash. A
|
|
||||||
page size of 64 bytes will waste 8-14% on metadata, while 256 bytes 2-4%.
|
|
||||||
So it seems it is good to select a big page size.
|
|
||||||
|
|
||||||
Also, spiffs uses a ram buffer being two times the page size. This ram buffer
|
|
||||||
is used for loading and manipulating pages, but it is also used for algorithms
|
|
||||||
to find free file ids, scanning the file system, etc. Having too small a page
|
|
||||||
size means less work buffer for spiffs, ending up in more reads operations and
|
|
||||||
eventually gives a slower file system.
|
|
||||||
|
|
||||||
Choosing the page size for the system involves many factors:
|
|
||||||
- How big is the logical block size
|
|
||||||
- What is the normal size of most files
|
|
||||||
- How much ram can be spent
|
|
||||||
- How much data (vs metadata) must be crammed into the file system
|
|
||||||
- How fast must spiffs be
|
|
||||||
- Other things impossible to find out
|
|
||||||
|
|
||||||
So, chosing the Optimal Page Size (tm) seems tricky, to say the least. Don't
|
|
||||||
fret - there is no optimal page size. This varies from how the target will use
|
|
||||||
spiffs. Use the golden rule:
|
|
||||||
|
|
||||||
~~~ Logical Page Size = Logical Block Size / 256 ~~~
|
|
||||||
|
|
||||||
This is a good starting point. The final page size can then be derived through
|
|
||||||
heuristical experimenting for us non-analytical minds.
|
|
||||||
|
|
||||||
|
|
||||||
** Objects, indices and look-ups
|
|
||||||
|
|
||||||
A file, or an object as called in spiffs, is identified by an object id.
|
|
||||||
Another YAFFS rip-off. This object id is a part of the page header. So, all
|
|
||||||
pages know to which object/file they belong - not counting the free pages.
|
|
||||||
|
|
||||||
An object is made up of two types of pages: object index pages and data pages.
|
|
||||||
Data pages contain the data written by user. Index pages contain metadata about
|
|
||||||
the object, more specifically what data pages are part of the object.
|
|
||||||
|
|
||||||
The page header also includes something called a span index. Let's say a file
|
|
||||||
is written covering three data pages. The first data page will then have span
|
|
||||||
index 0, the second span index 1, and the last data page will have span index
|
|
||||||
2. Simple as that.
|
|
||||||
|
|
||||||
Finally, each page header contain flags, telling if the page is used,
|
|
||||||
deleted, finalized, holds index or data, and more.
|
|
||||||
|
|
||||||
Object indices also have span indices, where an object index with span index 0
|
|
||||||
is referred to as the object index header. This page does not only contain
|
|
||||||
references to data pages, but also extra info such as object name, object size
|
|
||||||
in bytes, flags for file or directory, etc.
|
|
||||||
|
|
||||||
If one were to create a file covering three data pages, named e.g.
|
|
||||||
"spandex-joke.txt", given object id 12, it could look like this:
|
|
||||||
|
|
||||||
PAGE 0 <things to be unveiled soon>
|
|
||||||
|
|
||||||
PAGE 1 page header: [obj_id:12 span_ix:0 flags:USED|DATA]
|
|
||||||
<first data page of joke>
|
|
||||||
|
|
||||||
PAGE 2 page header: [obj_id:12 span_ix:1 flags:USED|DATA]
|
|
||||||
<second data page of joke>
|
|
||||||
|
|
||||||
PAGE 3 page header: [obj_id:545 span_ix:13 flags:USED|DATA]
|
|
||||||
<some data belonging to object 545, probably not very amusing>
|
|
||||||
|
|
||||||
PAGE 4 page header: [obj_id:12 span_ix:2 flags:USED|DATA]
|
|
||||||
<third data page of joke>
|
|
||||||
|
|
||||||
PAGE 5 page header: [obj_id:12 span_ix:0 flags:USED|INDEX]
|
|
||||||
obj ix header: [name:spandex-joke.txt size:600 bytes flags:FILE]
|
|
||||||
obj ix: [1 2 4]
|
|
||||||
|
|
||||||
Looking in detail at page 5, the object index header page, the object index
|
|
||||||
array refers to each data page in order, as mentioned before. The index of the
|
|
||||||
object index array correlates with the data page span index.
|
|
||||||
|
|
||||||
entry ix: 0 1 2
|
|
||||||
obj ix: [1 2 4]
|
|
||||||
| | |
|
|
||||||
PAGE 1, DATA, SPAN_IX 0 --------/ | |
|
|
||||||
PAGE 2, DATA, SPAN_IX 1 --------/ |
|
|
||||||
PAGE 4, DATA, SPAN_IX 2 --------/
|
|
||||||
|
|
||||||
Things to be unveiled in page 0 - well.. Spiffs is designed for systems low on
|
|
||||||
ram. We cannot keep a dynamic list on the whereabouts of each object index
|
|
||||||
header so we can find a file fast. There might not even be a heap! But, we do
|
|
||||||
not want to scan all page headers on the flash to find the object index header.
|
|
||||||
|
|
||||||
The first page(s) of each block contains the so called object look-up. These
|
|
||||||
are not normal pages, they do not have a header. Instead, they are arrays
|
|
||||||
pointing out what object-id the rest of all pages in the block belongs to.
|
|
||||||
|
|
||||||
By this look-up, only the first page(s) in each block must to scanned to find
|
|
||||||
the actual page which contains the object index header of the desired object.
|
|
||||||
|
|
||||||
The object lookup is redundant metadata. The assumption is that it presents
|
|
||||||
less overhead reading a full page of data to memory from each block and search
|
|
||||||
that, instead of reading a small amount of data from each page (i.e. the page
|
|
||||||
header) in all blocks. Each read operation from SPI flash normally contains
|
|
||||||
extra data as the read command itself and the flash address. Also, depending on
|
|
||||||
the underlying implementation, other criterions may need to be passed for each
|
|
||||||
read transaction, like mutexes and such.
|
|
||||||
|
|
||||||
The veiled example unveiled would look like this, with some extra pages:
|
|
||||||
|
|
||||||
PAGE 0 [ 12 12 545 12 12 34 34 4 0 0 0 0 ...]
|
|
||||||
PAGE 1 page header: [obj_id:12 span_ix:0 flags:USED|DATA] ...
|
|
||||||
PAGE 2 page header: [obj_id:12 span_ix:1 flags:USED|DATA] ...
|
|
||||||
PAGE 3 page header: [obj_id:545 span_ix:13 flags:USED|DATA] ...
|
|
||||||
PAGE 4 page header: [obj_id:12 span_ix:2 flags:USED|DATA] ...
|
|
||||||
PAGE 5 page header: [obj_id:12 span_ix:0 flags:USED|INDEX] ...
|
|
||||||
PAGE 6 page header: [obj_id:34 span_ix:0 flags:USED|DATA] ...
|
|
||||||
PAGE 7 page header: [obj_id:34 span_ix:1 flags:USED|DATA] ...
|
|
||||||
PAGE 8 page header: [obj_id:4 span_ix:1 flags:USED|INDEX] ...
|
|
||||||
PAGE 9 page header: [obj_id:23 span_ix:0 flags:DELETED|INDEX] ...
|
|
||||||
PAGE 10 page header: [obj_id:23 span_ix:0 flags:DELETED|DATA] ...
|
|
||||||
PAGE 11 page header: [obj_id:23 span_ix:1 flags:DELETED|DATA] ...
|
|
||||||
PAGE 12 page header: [obj_id:23 span_ix:2 flags:DELETED|DATA] ...
|
|
||||||
...
|
|
||||||
|
|
||||||
Ok, so why are page 9 to 12 marked as 0 when they belong to object id 23? These
|
|
||||||
pages are deleted, so this is marked both in page header flags and in the look
|
|
||||||
up. This is an example where spiffs uses NOR flashes "nand-way" of writing.
|
|
||||||
|
|
||||||
As a matter of fact, there are two object id's which are special:
|
|
||||||
|
|
||||||
obj id 0 (all bits zeroes) - indicates a deleted page in object look up
|
|
||||||
obj id 0xff.. (all bits ones) - indicates a free page in object look up
|
|
||||||
|
|
||||||
Actually, the object id's have another quirk: if the most significant bit is
|
|
||||||
set, this indicates an object index page. If the most significant bit is zero,
|
|
||||||
this indicates a data page. So to be fully correct, page 0 in above example
|
|
||||||
would look like this:
|
|
||||||
|
|
||||||
PAGE 0 [ 12 12 545 12 *12 34 34 *4 0 0 0 0 ...]
|
|
||||||
|
|
||||||
where the asterisk means the msb of the object id is set.
|
|
||||||
|
|
||||||
This is another way to speed up the searches when looking for object indices.
|
|
||||||
By looking on the object id's msb in the object lookup, it is also possible
|
|
||||||
to find out whether the page is an object index page or a data page.
|
|
||||||
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
* When mending lost pages, also see if they fit into length specified in object index header
|
|
||||||
|
|
||||||
SPIFFS2 thoughts
|
|
||||||
|
|
||||||
* Instead of exact object id:s in the object lookup tables, use a hash of span index and object id.
|
|
||||||
Eg. object id xor:ed with bit-reversed span index.
|
|
||||||
This should decrease number of actual pages that needs to be visited when looking thru the obj lut.
|
|
||||||
|
|
||||||
* Logical number of each block. When moving stuff in a garbage collected page, the free
|
|
||||||
page is assigned the same number as the garbage collected. Thus, object index pages do not have to
|
|
||||||
be rewritten.
|
|
||||||
|
|
||||||
* Steal one page, use as a bit parity page. When starting an fs modification operation, write one bit
|
|
||||||
as zero. When ending, write another bit as zero. On mount, if number of zeroes in page is uneven, a
|
|
||||||
check is automatically run.
|
|
||||||
@@ -1,681 +0,0 @@
|
|||||||
/*
|
|
||||||
* spiffs.h
|
|
||||||
*
|
|
||||||
* Created on: May 26, 2013
|
|
||||||
* Author: petera
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef SPIFFS_H_
|
|
||||||
#define SPIFFS_H_
|
|
||||||
#if defined(__cplusplus)
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "spiffs_config.h"
|
|
||||||
|
|
||||||
#define SPIFFS_OK 0
|
|
||||||
#define SPIFFS_ERR_NOT_MOUNTED -10000
|
|
||||||
#define SPIFFS_ERR_FULL -10001
|
|
||||||
#define SPIFFS_ERR_NOT_FOUND -10002
|
|
||||||
#define SPIFFS_ERR_END_OF_OBJECT -10003
|
|
||||||
#define SPIFFS_ERR_DELETED -10004
|
|
||||||
#define SPIFFS_ERR_NOT_FINALIZED -10005
|
|
||||||
#define SPIFFS_ERR_NOT_INDEX -10006
|
|
||||||
#define SPIFFS_ERR_OUT_OF_FILE_DESCS -10007
|
|
||||||
#define SPIFFS_ERR_FILE_CLOSED -10008
|
|
||||||
#define SPIFFS_ERR_FILE_DELETED -10009
|
|
||||||
#define SPIFFS_ERR_BAD_DESCRIPTOR -10010
|
|
||||||
#define SPIFFS_ERR_IS_INDEX -10011
|
|
||||||
#define SPIFFS_ERR_IS_FREE -10012
|
|
||||||
#define SPIFFS_ERR_INDEX_SPAN_MISMATCH -10013
|
|
||||||
#define SPIFFS_ERR_DATA_SPAN_MISMATCH -10014
|
|
||||||
#define SPIFFS_ERR_INDEX_REF_FREE -10015
|
|
||||||
#define SPIFFS_ERR_INDEX_REF_LU -10016
|
|
||||||
#define SPIFFS_ERR_INDEX_REF_INVALID -10017
|
|
||||||
#define SPIFFS_ERR_INDEX_FREE -10018
|
|
||||||
#define SPIFFS_ERR_INDEX_LU -10019
|
|
||||||
#define SPIFFS_ERR_INDEX_INVALID -10020
|
|
||||||
#define SPIFFS_ERR_NOT_WRITABLE -10021
|
|
||||||
#define SPIFFS_ERR_NOT_READABLE -10022
|
|
||||||
#define SPIFFS_ERR_CONFLICTING_NAME -10023
|
|
||||||
#define SPIFFS_ERR_NOT_CONFIGURED -10024
|
|
||||||
|
|
||||||
#define SPIFFS_ERR_NOT_A_FS -10025
|
|
||||||
#define SPIFFS_ERR_MOUNTED -10026
|
|
||||||
#define SPIFFS_ERR_ERASE_FAIL -10027
|
|
||||||
#define SPIFFS_ERR_MAGIC_NOT_POSSIBLE -10028
|
|
||||||
|
|
||||||
#define SPIFFS_ERR_NO_DELETED_BLOCKS -10029
|
|
||||||
|
|
||||||
#define SPIFFS_ERR_FILE_EXISTS -10030
|
|
||||||
|
|
||||||
#define SPIFFS_ERR_NOT_A_FILE -10031
|
|
||||||
#define SPIFFS_ERR_RO_NOT_IMPL -10032
|
|
||||||
#define SPIFFS_ERR_RO_ABORTED_OPERATION -10033
|
|
||||||
#define SPIFFS_ERR_PROBE_TOO_FEW_BLOCKS -10034
|
|
||||||
#define SPIFFS_ERR_PROBE_NOT_A_FS -10035
|
|
||||||
#define SPIFFS_ERR_INTERNAL -10050
|
|
||||||
|
|
||||||
#define SPIFFS_ERR_TEST -10100
|
|
||||||
|
|
||||||
|
|
||||||
// spiffs file descriptor index type. must be signed
|
|
||||||
typedef s16_t spiffs_file;
|
|
||||||
// spiffs file descriptor flags
|
|
||||||
typedef u16_t spiffs_flags;
|
|
||||||
// spiffs file mode
|
|
||||||
typedef u16_t spiffs_mode;
|
|
||||||
// object type
|
|
||||||
typedef u8_t spiffs_obj_type;
|
|
||||||
|
|
||||||
struct spiffs_t;
|
|
||||||
|
|
||||||
#if SPIFFS_HAL_CALLBACK_EXTRA
|
|
||||||
|
|
||||||
/* spi read call function type */
|
|
||||||
typedef s32_t (*spiffs_read)(struct spiffs_t *fs, u32_t addr, u32_t size, u8_t *dst);
|
|
||||||
/* spi write call function type */
|
|
||||||
typedef s32_t (*spiffs_write)(struct spiffs_t *fs, u32_t addr, u32_t size, u8_t *src);
|
|
||||||
/* spi erase call function type */
|
|
||||||
typedef s32_t (*spiffs_erase)(struct spiffs_t *fs, u32_t addr, u32_t size);
|
|
||||||
|
|
||||||
#else // SPIFFS_HAL_CALLBACK_EXTRA
|
|
||||||
|
|
||||||
/* spi read call function type */
|
|
||||||
typedef s32_t (*spiffs_read)(u32_t addr, u32_t size, u8_t *dst);
|
|
||||||
/* spi write call function type */
|
|
||||||
typedef s32_t (*spiffs_write)(u32_t addr, u32_t size, u8_t *src);
|
|
||||||
/* spi erase call function type */
|
|
||||||
typedef s32_t (*spiffs_erase)(u32_t addr, u32_t size);
|
|
||||||
#endif // SPIFFS_HAL_CALLBACK_EXTRA
|
|
||||||
|
|
||||||
/* file system check callback report operation */
|
|
||||||
typedef enum {
|
|
||||||
SPIFFS_CHECK_LOOKUP = 0,
|
|
||||||
SPIFFS_CHECK_INDEX,
|
|
||||||
SPIFFS_CHECK_PAGE
|
|
||||||
} spiffs_check_type;
|
|
||||||
|
|
||||||
/* file system check callback report type */
|
|
||||||
typedef enum {
|
|
||||||
SPIFFS_CHECK_PROGRESS = 0,
|
|
||||||
SPIFFS_CHECK_ERROR,
|
|
||||||
SPIFFS_CHECK_FIX_INDEX,
|
|
||||||
SPIFFS_CHECK_FIX_LOOKUP,
|
|
||||||
SPIFFS_CHECK_DELETE_ORPHANED_INDEX,
|
|
||||||
SPIFFS_CHECK_DELETE_PAGE,
|
|
||||||
SPIFFS_CHECK_DELETE_BAD_FILE,
|
|
||||||
} spiffs_check_report;
|
|
||||||
|
|
||||||
/* file system check callback function */
|
|
||||||
#if SPIFFS_HAL_CALLBACK_EXTRA
|
|
||||||
typedef void (*spiffs_check_callback)(struct spiffs_t *fs, spiffs_check_type type, spiffs_check_report report,
|
|
||||||
u32_t arg1, u32_t arg2);
|
|
||||||
#else // SPIFFS_HAL_CALLBACK_EXTRA
|
|
||||||
typedef void (*spiffs_check_callback)(spiffs_check_type type, spiffs_check_report report,
|
|
||||||
u32_t arg1, u32_t arg2);
|
|
||||||
#endif // SPIFFS_HAL_CALLBACK_EXTRA
|
|
||||||
|
|
||||||
/* file system listener callback operation */
|
|
||||||
typedef enum {
|
|
||||||
/* the file has been created */
|
|
||||||
SPIFFS_CB_CREATED = 0,
|
|
||||||
/* the file has been updated or moved to another page */
|
|
||||||
SPIFFS_CB_UPDATED,
|
|
||||||
/* the file has been deleted */
|
|
||||||
SPIFFS_CB_DELETED,
|
|
||||||
} spiffs_fileop_type;
|
|
||||||
|
|
||||||
/* file system listener callback function */
|
|
||||||
typedef void (*spiffs_file_callback)(struct spiffs_t *fs, spiffs_fileop_type op, spiffs_obj_id obj_id, spiffs_page_ix pix);
|
|
||||||
|
|
||||||
#ifndef SPIFFS_DBG
|
|
||||||
#define SPIFFS_DBG(...) \
|
|
||||||
print(__VA_ARGS__)
|
|
||||||
#endif
|
|
||||||
#ifndef SPIFFS_GC_DBG
|
|
||||||
#define SPIFFS_GC_DBG(...) printf(__VA_ARGS__)
|
|
||||||
#endif
|
|
||||||
#ifndef SPIFFS_CACHE_DBG
|
|
||||||
#define SPIFFS_CACHE_DBG(...) printf(__VA_ARGS__)
|
|
||||||
#endif
|
|
||||||
#ifndef SPIFFS_CHECK_DBG
|
|
||||||
#define SPIFFS_CHECK_DBG(...) printf(__VA_ARGS__)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Any write to the filehandle is appended to end of the file */
|
|
||||||
#define SPIFFS_APPEND (1<<0)
|
|
||||||
/* If the opened file exists, it will be truncated to zero length before opened */
|
|
||||||
#define SPIFFS_TRUNC (1<<1)
|
|
||||||
/* If the opened file does not exist, it will be created before opened */
|
|
||||||
#define SPIFFS_CREAT (1<<2)
|
|
||||||
/* The opened file may only be read */
|
|
||||||
#define SPIFFS_RDONLY (1<<3)
|
|
||||||
/* The opened file may only be writted */
|
|
||||||
#define SPIFFS_WRONLY (1<<4)
|
|
||||||
/* The opened file may be both read and writted */
|
|
||||||
#define SPIFFS_RDWR (SPIFFS_RDONLY | SPIFFS_WRONLY)
|
|
||||||
/* Any writes to the filehandle will never be cached */
|
|
||||||
#define SPIFFS_DIRECT (1<<5)
|
|
||||||
/* If SPIFFS_CREAT and SPIFFS_EXCL are set, SPIFFS_open() shall fail if the file exists */
|
|
||||||
#define SPIFFS_EXCL (1<<6)
|
|
||||||
|
|
||||||
#define SPIFFS_SEEK_SET (0)
|
|
||||||
#define SPIFFS_SEEK_CUR (1)
|
|
||||||
#define SPIFFS_SEEK_END (2)
|
|
||||||
|
|
||||||
#define SPIFFS_TYPE_FILE (1)
|
|
||||||
#define SPIFFS_TYPE_DIR (2)
|
|
||||||
#define SPIFFS_TYPE_HARD_LINK (3)
|
|
||||||
#define SPIFFS_TYPE_SOFT_LINK (4)
|
|
||||||
|
|
||||||
#ifndef SPIFFS_LOCK
|
|
||||||
#define SPIFFS_LOCK(fs)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef SPIFFS_UNLOCK
|
|
||||||
#define SPIFFS_UNLOCK(fs)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// phys structs
|
|
||||||
|
|
||||||
// spiffs spi configuration struct
|
|
||||||
typedef struct {
|
|
||||||
// physical read function
|
|
||||||
spiffs_read hal_read_f;
|
|
||||||
// physical write function
|
|
||||||
spiffs_write hal_write_f;
|
|
||||||
// physical erase function
|
|
||||||
spiffs_erase hal_erase_f;
|
|
||||||
#if SPIFFS_SINGLETON == 0
|
|
||||||
// physical size of the spi flash
|
|
||||||
u32_t phys_size;
|
|
||||||
// physical offset in spi flash used for spiffs,
|
|
||||||
// must be on block boundary
|
|
||||||
u32_t phys_addr;
|
|
||||||
// physical size when erasing a block
|
|
||||||
u32_t phys_erase_block;
|
|
||||||
|
|
||||||
// logical size of a block, must be on physical
|
|
||||||
// block size boundary and must never be less than
|
|
||||||
// a physical block
|
|
||||||
u32_t log_block_size;
|
|
||||||
// logical size of a page, must be at least
|
|
||||||
// log_block_size / 8
|
|
||||||
u32_t log_page_size;
|
|
||||||
|
|
||||||
#endif
|
|
||||||
#if SPIFFS_FILEHDL_OFFSET
|
|
||||||
// an integer offset added to each file handle
|
|
||||||
u16_t fh_ix_offset;
|
|
||||||
#endif
|
|
||||||
} spiffs_config;
|
|
||||||
|
|
||||||
typedef struct spiffs_t {
|
|
||||||
// file system configuration
|
|
||||||
spiffs_config cfg;
|
|
||||||
// number of logical blocks
|
|
||||||
u32_t block_count;
|
|
||||||
|
|
||||||
// cursor for free blocks, block index
|
|
||||||
spiffs_block_ix free_cursor_block_ix;
|
|
||||||
// cursor for free blocks, entry index
|
|
||||||
int free_cursor_obj_lu_entry;
|
|
||||||
// cursor when searching, block index
|
|
||||||
spiffs_block_ix cursor_block_ix;
|
|
||||||
// cursor when searching, entry index
|
|
||||||
int cursor_obj_lu_entry;
|
|
||||||
|
|
||||||
// primary work buffer, size of a logical page
|
|
||||||
u8_t *lu_work;
|
|
||||||
// secondary work buffer, size of a logical page
|
|
||||||
u8_t *work;
|
|
||||||
// file descriptor memory area
|
|
||||||
u8_t *fd_space;
|
|
||||||
// available file descriptors
|
|
||||||
u32_t fd_count;
|
|
||||||
|
|
||||||
// last error
|
|
||||||
s32_t err_code;
|
|
||||||
|
|
||||||
// current number of free blocks
|
|
||||||
u32_t free_blocks;
|
|
||||||
// current number of busy pages
|
|
||||||
u32_t stats_p_allocated;
|
|
||||||
// current number of deleted pages
|
|
||||||
u32_t stats_p_deleted;
|
|
||||||
// flag indicating that garbage collector is cleaning
|
|
||||||
u8_t cleaning;
|
|
||||||
// max erase count amongst all blocks
|
|
||||||
spiffs_obj_id max_erase_count;
|
|
||||||
|
|
||||||
#if SPIFFS_GC_STATS
|
|
||||||
u32_t stats_gc_runs;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if SPIFFS_CACHE
|
|
||||||
// cache memory
|
|
||||||
void *cache;
|
|
||||||
// cache size
|
|
||||||
u32_t cache_size;
|
|
||||||
#if SPIFFS_CACHE_STATS
|
|
||||||
u32_t cache_hits;
|
|
||||||
u32_t cache_misses;
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// check callback function
|
|
||||||
spiffs_check_callback check_cb_f;
|
|
||||||
// file callback function
|
|
||||||
spiffs_file_callback file_cb_f;
|
|
||||||
// mounted flag
|
|
||||||
u8_t mounted;
|
|
||||||
// user data
|
|
||||||
void *user_data;
|
|
||||||
// config magic
|
|
||||||
u32_t config_magic;
|
|
||||||
} spiffs;
|
|
||||||
|
|
||||||
/* spiffs file status struct */
|
|
||||||
typedef struct {
|
|
||||||
spiffs_obj_id obj_id;
|
|
||||||
u32_t size;
|
|
||||||
spiffs_obj_type type;
|
|
||||||
spiffs_page_ix pix;
|
|
||||||
u8_t name[SPIFFS_OBJ_NAME_LEN];
|
|
||||||
} spiffs_stat;
|
|
||||||
|
|
||||||
struct spiffs_dirent {
|
|
||||||
spiffs_obj_id obj_id;
|
|
||||||
u8_t name[SPIFFS_OBJ_NAME_LEN];
|
|
||||||
spiffs_obj_type type;
|
|
||||||
u32_t size;
|
|
||||||
spiffs_page_ix pix;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
spiffs *fs;
|
|
||||||
spiffs_block_ix block;
|
|
||||||
int entry;
|
|
||||||
} spiffs_DIR;
|
|
||||||
|
|
||||||
// functions
|
|
||||||
|
|
||||||
#if SPIFFS_USE_MAGIC && SPIFFS_USE_MAGIC_LENGTH && SPIFFS_SINGLETON==0
|
|
||||||
/**
|
|
||||||
* Special function. This takes a spiffs config struct and returns the number
|
|
||||||
* of blocks this file system was formatted with. This function relies on
|
|
||||||
* that following info is set correctly in given config struct:
|
|
||||||
*
|
|
||||||
* phys_addr, log_page_size, and log_block_size.
|
|
||||||
*
|
|
||||||
* Also, hal_read_f must be set in the config struct.
|
|
||||||
*
|
|
||||||
* One must be sure of the correct page size and that the physical address is
|
|
||||||
* correct in the probed file system when calling this function. It is not
|
|
||||||
* checked if the phys_addr actually points to the start of the file system,
|
|
||||||
* so one might get a false positive if entering a phys_addr somewhere in the
|
|
||||||
* middle of the file system at block boundary. In addition, it is not checked
|
|
||||||
* if the page size is actually correct. If it is not, weird file system sizes
|
|
||||||
* will be returned.
|
|
||||||
*
|
|
||||||
* If this function detects a file system it returns the assumed file system
|
|
||||||
* size, which can be used to set the phys_size.
|
|
||||||
*
|
|
||||||
* Otherwise, it returns an error indicating why it is not regarded as a file
|
|
||||||
* system.
|
|
||||||
*
|
|
||||||
* Note: this function is not protected with SPIFFS_LOCK and SPIFFS_UNLOCK
|
|
||||||
* macros. It returns the error code directly, instead of as read by
|
|
||||||
* SPIFFS_errno.
|
|
||||||
*
|
|
||||||
* @param config essential parts of the physical and logical
|
|
||||||
* configuration of the file system.
|
|
||||||
*/
|
|
||||||
s32_t SPIFFS_probe_fs(spiffs_config *config);
|
|
||||||
#endif // SPIFFS_USE_MAGIC && SPIFFS_USE_MAGIC_LENGTH && SPIFFS_SINGLETON==0
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initializes the file system dynamic parameters and mounts the filesystem.
|
|
||||||
* If SPIFFS_USE_MAGIC is enabled the mounting may fail with SPIFFS_ERR_NOT_A_FS
|
|
||||||
* if the flash does not contain a recognizable file system.
|
|
||||||
* In this case, SPIFFS_format must be called prior to remounting.
|
|
||||||
* @param fs the file system struct
|
|
||||||
* @param config the physical and logical configuration of the file system
|
|
||||||
* @param work a memory work buffer comprising 2*config->log_page_size
|
|
||||||
* bytes used throughout all file system operations
|
|
||||||
* @param fd_space memory for file descriptors
|
|
||||||
* @param fd_space_size memory size of file descriptors
|
|
||||||
* @param cache memory for cache, may be null
|
|
||||||
* @param cache_size memory size of cache
|
|
||||||
* @param check_cb_f callback function for reporting during consistency checks
|
|
||||||
*/
|
|
||||||
s32_t SPIFFS_mount(spiffs *fs, spiffs_config *config, u8_t *work,
|
|
||||||
u8_t *fd_space, u32_t fd_space_size,
|
|
||||||
void *cache, u32_t cache_size,
|
|
||||||
spiffs_check_callback check_cb_f);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Unmounts the file system. All file handles will be flushed of any
|
|
||||||
* cached writes and closed.
|
|
||||||
* @param fs the file system struct
|
|
||||||
*/
|
|
||||||
void SPIFFS_unmount(spiffs *fs);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new file.
|
|
||||||
* @param fs the file system struct
|
|
||||||
* @param path the path of the new file
|
|
||||||
* @param mode ignored, for posix compliance
|
|
||||||
*/
|
|
||||||
s32_t SPIFFS_creat(spiffs *fs, const char *path, spiffs_mode mode);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Opens/creates a file.
|
|
||||||
* @param fs the file system struct
|
|
||||||
* @param path the path of the new file
|
|
||||||
* @param flags the flags for the open command, can be combinations of
|
|
||||||
* SPIFFS_APPEND, SPIFFS_TRUNC, SPIFFS_CREAT, SPIFFS_RD_ONLY,
|
|
||||||
* SPIFFS_WR_ONLY, SPIFFS_RDWR, SPIFFS_DIRECT
|
|
||||||
* @param mode ignored, for posix compliance
|
|
||||||
*/
|
|
||||||
spiffs_file SPIFFS_open(spiffs *fs, const char *path, spiffs_flags flags, spiffs_mode mode);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Opens a file by given dir entry.
|
|
||||||
* Optimization purposes, when traversing a file system with SPIFFS_readdir
|
|
||||||
* a normal SPIFFS_open would need to traverse the filesystem again to find
|
|
||||||
* the file, whilst SPIFFS_open_by_dirent already knows where the file resides.
|
|
||||||
* @param fs the file system struct
|
|
||||||
* @param e the dir entry to the file
|
|
||||||
* @param flags the flags for the open command, can be combinations of
|
|
||||||
* SPIFFS_APPEND, SPIFFS_TRUNC, SPIFFS_CREAT, SPIFFS_RD_ONLY,
|
|
||||||
* SPIFFS_WR_ONLY, SPIFFS_RDWR, SPIFFS_DIRECT.
|
|
||||||
* SPIFFS_CREAT will have no effect in this case.
|
|
||||||
* @param mode ignored, for posix compliance
|
|
||||||
*/
|
|
||||||
spiffs_file SPIFFS_open_by_dirent(spiffs *fs, struct spiffs_dirent *e, spiffs_flags flags, spiffs_mode mode);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Opens a file by given page index.
|
|
||||||
* Optimization purposes, opens a file by directly pointing to the page
|
|
||||||
* index in the spi flash.
|
|
||||||
* If the page index does not point to a file header SPIFFS_ERR_NOT_A_FILE
|
|
||||||
* is returned.
|
|
||||||
* @param fs the file system struct
|
|
||||||
* @param page_ix the page index
|
|
||||||
* @param flags the flags for the open command, can be combinations of
|
|
||||||
* SPIFFS_APPEND, SPIFFS_TRUNC, SPIFFS_CREAT, SPIFFS_RD_ONLY,
|
|
||||||
* SPIFFS_WR_ONLY, SPIFFS_RDWR, SPIFFS_DIRECT.
|
|
||||||
* SPIFFS_CREAT will have no effect in this case.
|
|
||||||
* @param mode ignored, for posix compliance
|
|
||||||
*/
|
|
||||||
spiffs_file SPIFFS_open_by_page(spiffs *fs, spiffs_page_ix page_ix, spiffs_flags flags, spiffs_mode mode);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reads from given filehandle.
|
|
||||||
* @param fs the file system struct
|
|
||||||
* @param fh the filehandle
|
|
||||||
* @param buf where to put read data
|
|
||||||
* @param len how much to read
|
|
||||||
* @returns number of bytes read, or -1 if error
|
|
||||||
*/
|
|
||||||
s32_t SPIFFS_read(spiffs *fs, spiffs_file fh, void *buf, s32_t len);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Writes to given filehandle.
|
|
||||||
* @param fs the file system struct
|
|
||||||
* @param fh the filehandle
|
|
||||||
* @param buf the data to write
|
|
||||||
* @param len how much to write
|
|
||||||
* @returns number of bytes written, or -1 if error
|
|
||||||
*/
|
|
||||||
s32_t SPIFFS_write(spiffs *fs, spiffs_file fh, void *buf, s32_t len);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Moves the read/write file offset. Resulting offset is returned or negative if error.
|
|
||||||
* lseek(fs, fd, 0, SPIFFS_SEEK_CUR) will thus return current offset.
|
|
||||||
* @param fs the file system struct
|
|
||||||
* @param fh the filehandle
|
|
||||||
* @param offs how much/where to move the offset
|
|
||||||
* @param whence if SPIFFS_SEEK_SET, the file offset shall be set to offset bytes
|
|
||||||
* if SPIFFS_SEEK_CUR, the file offset shall be set to its current location plus offset
|
|
||||||
* if SPIFFS_SEEK_END, the file offset shall be set to the size of the file plus offse, which should be negative
|
|
||||||
*/
|
|
||||||
s32_t SPIFFS_lseek(spiffs *fs, spiffs_file fh, s32_t offs, int whence);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes a file by path
|
|
||||||
* @param fs the file system struct
|
|
||||||
* @param path the path of the file to remove
|
|
||||||
*/
|
|
||||||
s32_t SPIFFS_remove(spiffs *fs, const char *path);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes a file by filehandle
|
|
||||||
* @param fs the file system struct
|
|
||||||
* @param fh the filehandle of the file to remove
|
|
||||||
*/
|
|
||||||
s32_t SPIFFS_fremove(spiffs *fs, spiffs_file fh);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets file status by path
|
|
||||||
* @param fs the file system struct
|
|
||||||
* @param path the path of the file to stat
|
|
||||||
* @param s the stat struct to populate
|
|
||||||
*/
|
|
||||||
s32_t SPIFFS_stat(spiffs *fs, const char *path, spiffs_stat *s);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets file status by filehandle
|
|
||||||
* @param fs the file system struct
|
|
||||||
* @param fh the filehandle of the file to stat
|
|
||||||
* @param s the stat struct to populate
|
|
||||||
*/
|
|
||||||
s32_t SPIFFS_fstat(spiffs *fs, spiffs_file fh, spiffs_stat *s);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Flushes all pending write operations from cache for given file
|
|
||||||
* @param fs the file system struct
|
|
||||||
* @param fh the filehandle of the file to flush
|
|
||||||
*/
|
|
||||||
s32_t SPIFFS_fflush(spiffs *fs, spiffs_file fh);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Closes a filehandle. If there are pending write operations, these are finalized before closing.
|
|
||||||
* @param fs the file system struct
|
|
||||||
* @param fh the filehandle of the file to close
|
|
||||||
*/
|
|
||||||
s32_t SPIFFS_close(spiffs *fs, spiffs_file fh);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Renames a file
|
|
||||||
* @param fs the file system struct
|
|
||||||
* @param old path of file to rename
|
|
||||||
* @param newPath new path of file
|
|
||||||
*/
|
|
||||||
s32_t SPIFFS_rename(spiffs *fs, const char *old, const char *newPath);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns last error of last file operation.
|
|
||||||
* @param fs the file system struct
|
|
||||||
*/
|
|
||||||
s32_t SPIFFS_errno(spiffs *fs);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clears last error.
|
|
||||||
* @param fs the file system struct
|
|
||||||
*/
|
|
||||||
void SPIFFS_clearerr(spiffs *fs);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Opens a directory stream corresponding to the given name.
|
|
||||||
* The stream is positioned at the first entry in the directory.
|
|
||||||
* On hydrogen builds the name argument is ignored as hydrogen builds always correspond
|
|
||||||
* to a flat file structure - no directories.
|
|
||||||
* @param fs the file system struct
|
|
||||||
* @param name the name of the directory
|
|
||||||
* @param d pointer the directory stream to be populated
|
|
||||||
*/
|
|
||||||
spiffs_DIR *SPIFFS_opendir(spiffs *fs, const char *name, spiffs_DIR *d);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Closes a directory stream
|
|
||||||
* @param d the directory stream to close
|
|
||||||
*/
|
|
||||||
s32_t SPIFFS_closedir(spiffs_DIR *d);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reads a directory into given spifs_dirent struct.
|
|
||||||
* @param d pointer to the directory stream
|
|
||||||
* @param e the dirent struct to be populated
|
|
||||||
* @returns null if error or end of stream, else given dirent is returned
|
|
||||||
*/
|
|
||||||
struct spiffs_dirent *SPIFFS_readdir(spiffs_DIR *d, struct spiffs_dirent *e);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Runs a consistency check on given filesystem.
|
|
||||||
* @param fs the file system struct
|
|
||||||
*/
|
|
||||||
s32_t SPIFFS_check(spiffs *fs);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns number of total bytes available and number of used bytes.
|
|
||||||
* This is an estimation, and depends on if there a many files with little
|
|
||||||
* data or few files with much data.
|
|
||||||
* NB: If used number of bytes exceeds total bytes, a SPIFFS_check should
|
|
||||||
* run. This indicates a power loss in midst of things. In worst case
|
|
||||||
* (repeated powerlosses in mending or gc) you might have to delete some files.
|
|
||||||
*
|
|
||||||
* @param fs the file system struct
|
|
||||||
* @param total total number of bytes in filesystem
|
|
||||||
* @param used used number of bytes in filesystem
|
|
||||||
*/
|
|
||||||
s32_t SPIFFS_info(spiffs *fs, u32_t *total, u32_t *used);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Formats the entire file system. All data will be lost.
|
|
||||||
* The filesystem must not be mounted when calling this.
|
|
||||||
*
|
|
||||||
* NB: formatting is awkward. Due to backwards compatibility, SPIFFS_mount
|
|
||||||
* MUST be called prior to formatting in order to configure the filesystem.
|
|
||||||
* If SPIFFS_mount succeeds, SPIFFS_unmount must be called before calling
|
|
||||||
* SPIFFS_format.
|
|
||||||
* If SPIFFS_mount fails, SPIFFS_format can be called directly without calling
|
|
||||||
* SPIFFS_unmount first.
|
|
||||||
*
|
|
||||||
* @param fs the file system struct
|
|
||||||
*/
|
|
||||||
s32_t SPIFFS_format(spiffs *fs);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns nonzero if spiffs is mounted, or zero if unmounted.
|
|
||||||
* @param fs the file system struct
|
|
||||||
*/
|
|
||||||
u8_t SPIFFS_mounted(spiffs *fs);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tries to find a block where most or all pages are deleted, and erase that
|
|
||||||
* block if found. Does not care for wear levelling. Will not move pages
|
|
||||||
* around.
|
|
||||||
* If parameter max_free_pages are set to 0, only blocks with only deleted
|
|
||||||
* pages will be selected.
|
|
||||||
*
|
|
||||||
* NB: the garbage collector is automatically called when spiffs needs free
|
|
||||||
* pages. The reason for this function is to give possibility to do background
|
|
||||||
* tidying when user knows the system is idle.
|
|
||||||
*
|
|
||||||
* Use with care.
|
|
||||||
*
|
|
||||||
* Setting max_free_pages to anything larger than zero will eventually wear
|
|
||||||
* flash more as a block containing free pages can be erased.
|
|
||||||
*
|
|
||||||
* Will set err_no to SPIFFS_OK if a block was found and erased,
|
|
||||||
* SPIFFS_ERR_NO_DELETED_BLOCK if no matching block was found,
|
|
||||||
* or other error.
|
|
||||||
*
|
|
||||||
* @param fs the file system struct
|
|
||||||
* @param max_free_pages maximum number allowed free pages in block
|
|
||||||
*/
|
|
||||||
s32_t SPIFFS_gc_quick(spiffs *fs, u16_t max_free_pages);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Will try to make room for given amount of bytes in the filesystem by moving
|
|
||||||
* pages and erasing blocks.
|
|
||||||
* If it is physically impossible, err_no will be set to SPIFFS_ERR_FULL. If
|
|
||||||
* there already is this amount (or more) of free space, SPIFFS_gc will
|
|
||||||
* silently return. It is recommended to call SPIFFS_info before invoking
|
|
||||||
* this method in order to determine what amount of bytes to give.
|
|
||||||
*
|
|
||||||
* NB: the garbage collector is automatically called when spiffs needs free
|
|
||||||
* pages. The reason for this function is to give possibility to do background
|
|
||||||
* tidying when user knows the system is idle.
|
|
||||||
*
|
|
||||||
* Use with care.
|
|
||||||
*
|
|
||||||
* @param fs the file system struct
|
|
||||||
* @param size amount of bytes that should be freed
|
|
||||||
*/
|
|
||||||
s32_t SPIFFS_gc(spiffs *fs, u32_t size);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if EOF reached.
|
|
||||||
* @param fs the file system struct
|
|
||||||
* @param fh the filehandle of the file to check
|
|
||||||
*/
|
|
||||||
s32_t SPIFFS_eof(spiffs *fs, spiffs_file fh);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get position in file.
|
|
||||||
* @param fs the file system struct
|
|
||||||
* @param fh the filehandle of the file to check
|
|
||||||
*/
|
|
||||||
s32_t SPIFFS_tell(spiffs *fs, spiffs_file fh);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Registers a callback function that keeps track on operations on file
|
|
||||||
* headers. Do note, that this callback is called from within internal spiffs
|
|
||||||
* mechanisms. Any operations on the actual file system being callbacked from
|
|
||||||
* in this callback will mess things up for sure - do not do this.
|
|
||||||
* This can be used to track where files are and move around during garbage
|
|
||||||
* collection, which in turn can be used to build location tables in ram.
|
|
||||||
* Used in conjuction with SPIFFS_open_by_page this may improve performance
|
|
||||||
* when opening a lot of files.
|
|
||||||
* Must be invoked after mount.
|
|
||||||
*
|
|
||||||
* @param fs the file system struct
|
|
||||||
* @param cb_func the callback on file operations
|
|
||||||
*/
|
|
||||||
s32_t SPIFFS_set_file_callback_func(spiffs *fs, spiffs_file_callback cb_func);
|
|
||||||
|
|
||||||
#if SPIFFS_TEST_VISUALISATION
|
|
||||||
/**
|
|
||||||
* Prints out a visualization of the filesystem.
|
|
||||||
* @param fs the file system struct
|
|
||||||
*/
|
|
||||||
s32_t SPIFFS_vis(spiffs *fs);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if SPIFFS_BUFFER_HELP
|
|
||||||
/**
|
|
||||||
* Returns number of bytes needed for the filedescriptor buffer given
|
|
||||||
* amount of file descriptors.
|
|
||||||
*/
|
|
||||||
u32_t SPIFFS_buffer_bytes_for_filedescs(spiffs *fs, u32_t num_descs);
|
|
||||||
|
|
||||||
#if SPIFFS_CACHE
|
|
||||||
/**
|
|
||||||
* Returns number of bytes needed for the cache buffer given
|
|
||||||
* amount of cache pages.
|
|
||||||
*/
|
|
||||||
u32_t SPIFFS_buffer_bytes_for_cache(spiffs *fs, u32_t num_pages);
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if SPIFFS_CACHE
|
|
||||||
#endif
|
|
||||||
#if defined(__cplusplus)
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* SPIFFS_H_ */
|
|
||||||
@@ -1,299 +0,0 @@
|
|||||||
/*
|
|
||||||
* spiffs_cache.c
|
|
||||||
*
|
|
||||||
* Created on: Jun 23, 2013
|
|
||||||
* Author: petera
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "spiffs.h"
|
|
||||||
#include "spiffs_nucleus.h"
|
|
||||||
|
|
||||||
#if SPIFFS_CACHE
|
|
||||||
|
|
||||||
// returns cached page for give page index, or null if no such cached page
|
|
||||||
static spiffs_cache_page *spiffs_cache_page_get(spiffs *fs, spiffs_page_ix pix) {
|
|
||||||
spiffs_cache *cache = spiffs_get_cache(fs);
|
|
||||||
if ((cache->cpage_use_map & cache->cpage_use_mask) == 0) return 0;
|
|
||||||
int i;
|
|
||||||
for (i = 0; i < cache->cpage_count; i++) {
|
|
||||||
spiffs_cache_page *cp = spiffs_get_cache_page_hdr(fs, cache, i);
|
|
||||||
if ((cache->cpage_use_map & (1<<i)) &&
|
|
||||||
(cp->flags & SPIFFS_CACHE_FLAG_TYPE_WR) == 0 &&
|
|
||||||
cp->pix == pix ) {
|
|
||||||
SPIFFS_CACHE_DBG("CACHE_GET: have cache page %i for %04x\n", i, pix);
|
|
||||||
cp->last_access = cache->last_access;
|
|
||||||
return cp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//SPIFFS_CACHE_DBG("CACHE_GET: no cache for %04x\n", pix);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// frees cached page
|
|
||||||
static s32_t spiffs_cache_page_free(spiffs *fs, int ix, u8_t write_back) {
|
|
||||||
s32_t res = SPIFFS_OK;
|
|
||||||
spiffs_cache *cache = spiffs_get_cache(fs);
|
|
||||||
spiffs_cache_page *cp = spiffs_get_cache_page_hdr(fs, cache, ix);
|
|
||||||
if (cache->cpage_use_map & (1<<ix)) {
|
|
||||||
if (write_back &&
|
|
||||||
(cp->flags & SPIFFS_CACHE_FLAG_TYPE_WR) == 0 &&
|
|
||||||
(cp->flags & SPIFFS_CACHE_FLAG_DIRTY)) {
|
|
||||||
u8_t *mem = spiffs_get_cache_page(fs, cache, ix);
|
|
||||||
res = SPIFFS_HAL_WRITE(fs, SPIFFS_PAGE_TO_PADDR(fs, cp->pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), mem);
|
|
||||||
}
|
|
||||||
|
|
||||||
cp->flags = 0;
|
|
||||||
cache->cpage_use_map &= ~(1 << ix);
|
|
||||||
|
|
||||||
if (cp->flags & SPIFFS_CACHE_FLAG_TYPE_WR) {
|
|
||||||
SPIFFS_CACHE_DBG("CACHE_FREE: free cache page %i objid %04x\n", ix, cp->obj_id);
|
|
||||||
} else {
|
|
||||||
SPIFFS_CACHE_DBG("CACHE_FREE: free cache page %i pix %04x\n", ix, cp->pix);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
// removes the oldest accessed cached page
|
|
||||||
static s32_t spiffs_cache_page_remove_oldest(spiffs *fs, u8_t flag_mask, u8_t flags) {
|
|
||||||
s32_t res = SPIFFS_OK;
|
|
||||||
spiffs_cache *cache = spiffs_get_cache(fs);
|
|
||||||
|
|
||||||
if ((cache->cpage_use_map & cache->cpage_use_mask) != cache->cpage_use_mask) {
|
|
||||||
// at least one free cpage
|
|
||||||
return SPIFFS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
// all busy, scan thru all to find the cpage which has oldest access
|
|
||||||
int i;
|
|
||||||
int cand_ix = -1;
|
|
||||||
u32_t oldest_val = 0;
|
|
||||||
for (i = 0; i < cache->cpage_count; i++) {
|
|
||||||
spiffs_cache_page *cp = spiffs_get_cache_page_hdr(fs, cache, i);
|
|
||||||
if ((cache->last_access - cp->last_access) > oldest_val &&
|
|
||||||
(cp->flags & flag_mask) == flags) {
|
|
||||||
oldest_val = cache->last_access - cp->last_access;
|
|
||||||
cand_ix = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cand_ix >= 0) {
|
|
||||||
res = spiffs_cache_page_free(fs, cand_ix, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
// allocates a new cached page and returns it, or null if all cache pages are busy
|
|
||||||
static spiffs_cache_page *spiffs_cache_page_allocate(spiffs *fs) {
|
|
||||||
spiffs_cache *cache = spiffs_get_cache(fs);
|
|
||||||
if (cache->cpage_use_map == 0xffffffff) {
|
|
||||||
// out of cache memory
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
int i;
|
|
||||||
for (i = 0; i < cache->cpage_count; i++) {
|
|
||||||
if ((cache->cpage_use_map & (1<<i)) == 0) {
|
|
||||||
spiffs_cache_page *cp = spiffs_get_cache_page_hdr(fs, cache, i);
|
|
||||||
cache->cpage_use_map |= (1<<i);
|
|
||||||
cp->last_access = cache->last_access;
|
|
||||||
SPIFFS_CACHE_DBG("CACHE_ALLO: allocated cache page %i\n", i);
|
|
||||||
return cp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// out of cache entries
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// drops the cache page for give page index
|
|
||||||
void spiffs_cache_drop_page(spiffs *fs, spiffs_page_ix pix) {
|
|
||||||
spiffs_cache_page *cp = spiffs_cache_page_get(fs, pix);
|
|
||||||
if (cp) {
|
|
||||||
spiffs_cache_page_free(fs, cp->ix, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------------------
|
|
||||||
|
|
||||||
// reads from spi flash or the cache
|
|
||||||
s32_t spiffs_phys_rd(
|
|
||||||
spiffs *fs,
|
|
||||||
u8_t op,
|
|
||||||
spiffs_file fh,
|
|
||||||
u32_t addr,
|
|
||||||
u32_t len,
|
|
||||||
u8_t *dst) {
|
|
||||||
(void)fh;
|
|
||||||
s32_t res = SPIFFS_OK;
|
|
||||||
spiffs_cache *cache = spiffs_get_cache(fs);
|
|
||||||
spiffs_cache_page *cp = spiffs_cache_page_get(fs, SPIFFS_PADDR_TO_PAGE(fs, addr));
|
|
||||||
cache->last_access++;
|
|
||||||
if (cp) {
|
|
||||||
#if SPIFFS_CACHE_STATS
|
|
||||||
fs->cache_hits++;
|
|
||||||
#endif
|
|
||||||
cp->last_access = cache->last_access;
|
|
||||||
} else {
|
|
||||||
if ((op & SPIFFS_OP_TYPE_MASK) == SPIFFS_OP_T_OBJ_LU2) {
|
|
||||||
// for second layer lookup functions, we do not cache in order to prevent shredding
|
|
||||||
return SPIFFS_HAL_READ(fs, addr, len, dst);
|
|
||||||
}
|
|
||||||
#if SPIFFS_CACHE_STATS
|
|
||||||
fs->cache_misses++;
|
|
||||||
#endif
|
|
||||||
res = spiffs_cache_page_remove_oldest(fs, SPIFFS_CACHE_FLAG_TYPE_WR, 0);
|
|
||||||
cp = spiffs_cache_page_allocate(fs);
|
|
||||||
if (cp) {
|
|
||||||
cp->flags = SPIFFS_CACHE_FLAG_WRTHRU;
|
|
||||||
cp->pix = SPIFFS_PADDR_TO_PAGE(fs, addr);
|
|
||||||
}
|
|
||||||
s32_t res2 = SPIFFS_HAL_READ(fs,
|
|
||||||
addr - SPIFFS_PADDR_TO_PAGE_OFFSET(fs, addr),
|
|
||||||
SPIFFS_CFG_LOG_PAGE_SZ(fs),
|
|
||||||
spiffs_get_cache_page(fs, cache, cp->ix));
|
|
||||||
if (res2 != SPIFFS_OK) {
|
|
||||||
res = res2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
u8_t *mem = spiffs_get_cache_page(fs, cache, cp->ix);
|
|
||||||
memcpy(dst, &mem[SPIFFS_PADDR_TO_PAGE_OFFSET(fs, addr)], len);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
// writes to spi flash and/or the cache
|
|
||||||
s32_t spiffs_phys_wr(
|
|
||||||
spiffs *fs,
|
|
||||||
u8_t op,
|
|
||||||
spiffs_file fh,
|
|
||||||
u32_t addr,
|
|
||||||
u32_t len,
|
|
||||||
u8_t *src) {
|
|
||||||
(void)fh;
|
|
||||||
spiffs_page_ix pix = SPIFFS_PADDR_TO_PAGE(fs, addr);
|
|
||||||
spiffs_cache *cache = spiffs_get_cache(fs);
|
|
||||||
spiffs_cache_page *cp = spiffs_cache_page_get(fs, pix);
|
|
||||||
|
|
||||||
if (cp && (op & SPIFFS_OP_COM_MASK) != SPIFFS_OP_C_WRTHRU) {
|
|
||||||
// have a cache page
|
|
||||||
// copy in data to cache page
|
|
||||||
|
|
||||||
if ((op & SPIFFS_OP_COM_MASK) == SPIFFS_OP_C_DELE &&
|
|
||||||
(op & SPIFFS_OP_TYPE_MASK) != SPIFFS_OP_T_OBJ_LU) {
|
|
||||||
// page is being deleted, wipe from cache - unless it is a lookup page
|
|
||||||
spiffs_cache_page_free(fs, cp->ix, 0);
|
|
||||||
return SPIFFS_HAL_WRITE(fs, addr, len, src);
|
|
||||||
}
|
|
||||||
|
|
||||||
u8_t *mem = spiffs_get_cache_page(fs, cache, cp->ix);
|
|
||||||
memcpy(&mem[SPIFFS_PADDR_TO_PAGE_OFFSET(fs, addr)], src, len);
|
|
||||||
|
|
||||||
cache->last_access++;
|
|
||||||
cp->last_access = cache->last_access;
|
|
||||||
|
|
||||||
if (cp->flags & SPIFFS_CACHE_FLAG_WRTHRU) {
|
|
||||||
// page is being updated, no write-cache, just pass thru
|
|
||||||
return SPIFFS_HAL_WRITE(fs, addr, len, src);
|
|
||||||
} else {
|
|
||||||
return SPIFFS_OK;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// no cache page, no write cache - just write thru
|
|
||||||
return SPIFFS_HAL_WRITE(fs, addr, len, src);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if SPIFFS_CACHE_WR
|
|
||||||
// returns the cache page that this fd refers, or null if no cache page
|
|
||||||
spiffs_cache_page *spiffs_cache_page_get_by_fd(spiffs *fs, spiffs_fd *fd) {
|
|
||||||
spiffs_cache *cache = spiffs_get_cache(fs);
|
|
||||||
|
|
||||||
if ((cache->cpage_use_map & cache->cpage_use_mask) == 0) {
|
|
||||||
// all cpages free, no cpage cannot be assigned to obj_id
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int i;
|
|
||||||
for (i = 0; i < cache->cpage_count; i++) {
|
|
||||||
spiffs_cache_page *cp = spiffs_get_cache_page_hdr(fs, cache, i);
|
|
||||||
if ((cache->cpage_use_map & (1<<i)) &&
|
|
||||||
(cp->flags & SPIFFS_CACHE_FLAG_TYPE_WR) &&
|
|
||||||
cp->obj_id == fd->obj_id) {
|
|
||||||
return cp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// allocates a new cache page and refers this to given fd - flushes an old cache
|
|
||||||
// page if all cache is busy
|
|
||||||
spiffs_cache_page *spiffs_cache_page_allocate_by_fd(spiffs *fs, spiffs_fd *fd) {
|
|
||||||
// before this function is called, it is ensured that there is no already existing
|
|
||||||
// cache page with same object id
|
|
||||||
spiffs_cache_page_remove_oldest(fs, SPIFFS_CACHE_FLAG_TYPE_WR, 0);
|
|
||||||
spiffs_cache_page *cp = spiffs_cache_page_allocate(fs);
|
|
||||||
if (cp == 0) {
|
|
||||||
// could not get cache page
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
cp->flags = SPIFFS_CACHE_FLAG_TYPE_WR;
|
|
||||||
cp->obj_id = fd->obj_id;
|
|
||||||
fd->cache_page = cp;
|
|
||||||
return cp;
|
|
||||||
}
|
|
||||||
|
|
||||||
// unrefers all fds that this cache page refers to and releases the cache page
|
|
||||||
void spiffs_cache_fd_release(spiffs *fs, spiffs_cache_page *cp) {
|
|
||||||
if (cp == 0) return;
|
|
||||||
u32_t i;
|
|
||||||
spiffs_fd *fds = (spiffs_fd *)fs->fd_space;
|
|
||||||
for (i = 0; i < fs->fd_count; i++) {
|
|
||||||
spiffs_fd *cur_fd = &fds[i];
|
|
||||||
if (cur_fd->file_nbr != 0 && cur_fd->cache_page == cp) {
|
|
||||||
cur_fd->cache_page = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
spiffs_cache_page_free(fs, cp->ix, 0);
|
|
||||||
|
|
||||||
cp->obj_id = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// initializes the cache
|
|
||||||
void spiffs_cache_init(spiffs *fs) {
|
|
||||||
if (fs->cache == 0) return;
|
|
||||||
u32_t sz = fs->cache_size;
|
|
||||||
u32_t cache_mask = 0;
|
|
||||||
int i;
|
|
||||||
int cache_entries =
|
|
||||||
(sz - sizeof(spiffs_cache)) / (SPIFFS_CACHE_PAGE_SIZE(fs));
|
|
||||||
if (cache_entries <= 0) return;
|
|
||||||
|
|
||||||
for (i = 0; i < cache_entries; i++) {
|
|
||||||
cache_mask <<= 1;
|
|
||||||
cache_mask |= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
spiffs_cache cache;
|
|
||||||
memset(&cache, 0, sizeof(spiffs_cache));
|
|
||||||
cache.cpage_count = cache_entries;
|
|
||||||
cache.cpages = (u8_t *)((u8_t *)fs->cache + sizeof(spiffs_cache));
|
|
||||||
|
|
||||||
cache.cpage_use_map = 0xffffffff;
|
|
||||||
cache.cpage_use_mask = cache_mask;
|
|
||||||
memcpy(fs->cache, &cache, sizeof(spiffs_cache));
|
|
||||||
|
|
||||||
spiffs_cache *c = spiffs_get_cache(fs);
|
|
||||||
|
|
||||||
memset(c->cpages, 0, c->cpage_count * SPIFFS_CACHE_PAGE_SIZE(fs));
|
|
||||||
|
|
||||||
c->cpage_use_map &= ~(c->cpage_use_mask);
|
|
||||||
for (i = 0; i < cache.cpage_count; i++) {
|
|
||||||
spiffs_get_cache_page_hdr(fs, c, i)->ix = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // SPIFFS_CACHE
|
|
||||||
@@ -1,995 +0,0 @@
|
|||||||
/*
|
|
||||||
* spiffs_check.c
|
|
||||||
*
|
|
||||||
* Contains functionality for checking file system consistency
|
|
||||||
* and mending problems.
|
|
||||||
* Three levels of consistency checks are implemented:
|
|
||||||
*
|
|
||||||
* Look up consistency
|
|
||||||
* Checks if indices in lookup pages are coherent with page headers
|
|
||||||
* Object index consistency
|
|
||||||
* Checks if there are any orphaned object indices (missing object index headers).
|
|
||||||
* If an object index is found but not its header, the object index is deleted.
|
|
||||||
* This is critical for the following page consistency check.
|
|
||||||
* Page consistency
|
|
||||||
* Checks for pages that ought to be indexed, ought not to be indexed, are multiple indexed
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* Created on: Jul 7, 2013
|
|
||||||
* Author: petera
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#include "spiffs.h"
|
|
||||||
#include "spiffs_nucleus.h"
|
|
||||||
|
|
||||||
#if !SPIFFS_READ_ONLY
|
|
||||||
|
|
||||||
#if SPIFFS_HAL_CALLBACK_EXTRA
|
|
||||||
#define CHECK_CB(_fs, _type, _rep, _arg1, _arg2) \
|
|
||||||
do { \
|
|
||||||
if ((_fs)->check_cb_f) (_fs)->check_cb_f((_fs), (_type), (_rep), (_arg1), (_arg2)); \
|
|
||||||
} while (0)
|
|
||||||
#else
|
|
||||||
#define CHECK_CB(_fs, _type, _rep, _arg1, _arg2) \
|
|
||||||
do { \
|
|
||||||
if ((_fs)->check_cb_f) (_fs)->check_cb_f((_type), (_rep), (_arg1), (_arg2)); \
|
|
||||||
} while (0)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//---------------------------------------
|
|
||||||
// Look up consistency
|
|
||||||
|
|
||||||
// searches in the object indices and returns the referenced page index given
|
|
||||||
// the object id and the data span index
|
|
||||||
// destroys fs->lu_work
|
|
||||||
static s32_t spiffs_object_get_data_page_index_reference(
|
|
||||||
spiffs *fs,
|
|
||||||
spiffs_obj_id obj_id,
|
|
||||||
spiffs_span_ix data_spix,
|
|
||||||
spiffs_page_ix *pix,
|
|
||||||
spiffs_page_ix *objix_pix) {
|
|
||||||
s32_t res;
|
|
||||||
|
|
||||||
// calculate object index span index for given data page span index
|
|
||||||
spiffs_span_ix objix_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, data_spix);
|
|
||||||
|
|
||||||
// find obj index for obj id and span index
|
|
||||||
res = spiffs_obj_lu_find_id_and_span(fs, obj_id | SPIFFS_OBJ_ID_IX_FLAG, objix_spix, 0, objix_pix);
|
|
||||||
SPIFFS_CHECK_RES(res);
|
|
||||||
|
|
||||||
// load obj index entry
|
|
||||||
u32_t addr = SPIFFS_PAGE_TO_PADDR(fs, *objix_pix);
|
|
||||||
if (objix_spix == 0) {
|
|
||||||
// get referenced page from object index header
|
|
||||||
addr += sizeof(spiffs_page_object_ix_header) + data_spix * sizeof(spiffs_page_ix);
|
|
||||||
} else {
|
|
||||||
// get referenced page from object index
|
|
||||||
addr += sizeof(spiffs_page_object_ix) + SPIFFS_OBJ_IX_ENTRY(fs, data_spix) * sizeof(spiffs_page_ix);
|
|
||||||
}
|
|
||||||
|
|
||||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ, 0, addr, sizeof(spiffs_page_ix), (u8_t *)pix);
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
// copies page contents to a new page
|
|
||||||
static s32_t spiffs_rewrite_page(spiffs *fs, spiffs_page_ix cur_pix, spiffs_page_header *p_hdr, spiffs_page_ix *new_pix) {
|
|
||||||
s32_t res;
|
|
||||||
res = spiffs_page_allocate_data(fs, p_hdr->obj_id, p_hdr, 0,0,0,0, new_pix);
|
|
||||||
SPIFFS_CHECK_RES(res);
|
|
||||||
res = spiffs_phys_cpy(fs, 0,
|
|
||||||
SPIFFS_PAGE_TO_PADDR(fs, *new_pix) + sizeof(spiffs_page_header),
|
|
||||||
SPIFFS_PAGE_TO_PADDR(fs, cur_pix) + sizeof(spiffs_page_header),
|
|
||||||
SPIFFS_DATA_PAGE_SIZE(fs));
|
|
||||||
SPIFFS_CHECK_RES(res);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
// rewrites the object index for given object id and replaces the
|
|
||||||
// data page index to a new page index
|
|
||||||
static s32_t spiffs_rewrite_index(spiffs *fs, spiffs_obj_id obj_id, spiffs_span_ix data_spix, spiffs_page_ix new_data_pix, spiffs_page_ix objix_pix) {
|
|
||||||
s32_t res;
|
|
||||||
spiffs_block_ix bix;
|
|
||||||
int entry;
|
|
||||||
spiffs_page_ix free_pix;
|
|
||||||
obj_id |= SPIFFS_OBJ_ID_IX_FLAG;
|
|
||||||
|
|
||||||
// find free entry
|
|
||||||
res = spiffs_obj_lu_find_free(fs, fs->free_cursor_block_ix, fs->free_cursor_obj_lu_entry, &bix, &entry);
|
|
||||||
SPIFFS_CHECK_RES(res);
|
|
||||||
free_pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, entry);
|
|
||||||
|
|
||||||
// calculate object index span index for given data page span index
|
|
||||||
spiffs_span_ix objix_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, data_spix);
|
|
||||||
if (objix_spix == 0) {
|
|
||||||
// calc index in index header
|
|
||||||
entry = data_spix;
|
|
||||||
} else {
|
|
||||||
// calc entry in index
|
|
||||||
entry = SPIFFS_OBJ_IX_ENTRY(fs, data_spix);
|
|
||||||
|
|
||||||
}
|
|
||||||
// load index
|
|
||||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
|
|
||||||
0, SPIFFS_PAGE_TO_PADDR(fs, objix_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);
|
|
||||||
SPIFFS_CHECK_RES(res);
|
|
||||||
spiffs_page_header *objix_p_hdr = (spiffs_page_header *)fs->lu_work;
|
|
||||||
|
|
||||||
// be ultra safe, double check header against provided data
|
|
||||||
if (objix_p_hdr->obj_id != obj_id) {
|
|
||||||
spiffs_page_delete(fs, free_pix);
|
|
||||||
return SPIFFS_ERR_CHECK_OBJ_ID_MISM;
|
|
||||||
}
|
|
||||||
if (objix_p_hdr->span_ix != objix_spix) {
|
|
||||||
spiffs_page_delete(fs, free_pix);
|
|
||||||
return SPIFFS_ERR_CHECK_SPIX_MISM;
|
|
||||||
}
|
|
||||||
if ((objix_p_hdr->flags & (SPIFFS_PH_FLAG_USED | SPIFFS_PH_FLAG_IXDELE | SPIFFS_PH_FLAG_INDEX |
|
|
||||||
SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_DELET)) !=
|
|
||||||
(SPIFFS_PH_FLAG_IXDELE | SPIFFS_PH_FLAG_DELET)) {
|
|
||||||
spiffs_page_delete(fs, free_pix);
|
|
||||||
return SPIFFS_ERR_CHECK_FLAGS_BAD;
|
|
||||||
}
|
|
||||||
|
|
||||||
// rewrite in mem
|
|
||||||
if (objix_spix == 0) {
|
|
||||||
((spiffs_page_ix*)((u8_t *)fs->lu_work + sizeof(spiffs_page_object_ix_header)))[data_spix] = new_data_pix;
|
|
||||||
} else {
|
|
||||||
((spiffs_page_ix*)((u8_t *)fs->lu_work + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, data_spix)] = new_data_pix;
|
|
||||||
}
|
|
||||||
|
|
||||||
res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT,
|
|
||||||
0, SPIFFS_PAGE_TO_PADDR(fs, free_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);
|
|
||||||
SPIFFS_CHECK_RES(res);
|
|
||||||
res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_UPDT,
|
|
||||||
0, SPIFFS_BLOCK_TO_PADDR(fs, SPIFFS_BLOCK_FOR_PAGE(fs, free_pix)) + SPIFFS_OBJ_LOOKUP_ENTRY_FOR_PAGE(fs, free_pix) * sizeof(spiffs_page_ix),
|
|
||||||
sizeof(spiffs_obj_id),
|
|
||||||
(u8_t *)&obj_id);
|
|
||||||
SPIFFS_CHECK_RES(res);
|
|
||||||
res = spiffs_page_delete(fs, objix_pix);
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
// deletes an object just by marking object index header as deleted
|
|
||||||
static s32_t spiffs_delete_obj_lazy(spiffs *fs, spiffs_obj_id obj_id) {
|
|
||||||
spiffs_page_ix objix_hdr_pix;
|
|
||||||
s32_t res;
|
|
||||||
res = spiffs_obj_lu_find_id_and_span(fs, obj_id, 0, 0, &objix_hdr_pix);
|
|
||||||
if (res == SPIFFS_ERR_NOT_FOUND) {
|
|
||||||
return SPIFFS_OK;
|
|
||||||
}
|
|
||||||
SPIFFS_CHECK_RES(res);
|
|
||||||
u8_t flags = 0xff & ~SPIFFS_PH_FLAG_IXDELE;
|
|
||||||
res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_UPDT,
|
|
||||||
0, SPIFFS_PAGE_TO_PADDR(fs, objix_hdr_pix) + offsetof(spiffs_page_header, flags),
|
|
||||||
sizeof(u8_t),
|
|
||||||
(u8_t *)&flags);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
// validates the given look up entry
|
|
||||||
static s32_t spiffs_lookup_check_validate(spiffs *fs, spiffs_obj_id lu_obj_id, spiffs_page_header *p_hdr,
|
|
||||||
spiffs_page_ix cur_pix, spiffs_block_ix cur_block, int cur_entry, int *reload_lu) {
|
|
||||||
(void)cur_block;
|
|
||||||
(void)cur_entry;
|
|
||||||
u8_t delete_page = 0;
|
|
||||||
s32_t res = SPIFFS_OK;
|
|
||||||
spiffs_page_ix objix_pix;
|
|
||||||
spiffs_page_ix ref_pix;
|
|
||||||
// check validity, take actions
|
|
||||||
if (((lu_obj_id == SPIFFS_OBJ_ID_DELETED) && (p_hdr->flags & SPIFFS_PH_FLAG_DELET)) ||
|
|
||||||
((lu_obj_id == SPIFFS_OBJ_ID_FREE) && (p_hdr->flags & SPIFFS_PH_FLAG_USED) == 0)) {
|
|
||||||
// look up entry deleted / free but used in page header
|
|
||||||
SPIFFS_CHECK_DBG("LU: pix %04x deleted/free in lu but not on page\n", cur_pix);
|
|
||||||
*reload_lu = 1;
|
|
||||||
delete_page = 1;
|
|
||||||
if (p_hdr->flags & SPIFFS_PH_FLAG_INDEX) {
|
|
||||||
// header says data page
|
|
||||||
// data page can be removed if not referenced by some object index
|
|
||||||
res = spiffs_object_get_data_page_index_reference(fs, p_hdr->obj_id, p_hdr->span_ix, &ref_pix, &objix_pix);
|
|
||||||
if (res == SPIFFS_ERR_NOT_FOUND) {
|
|
||||||
// no object with this id, so remove page safely
|
|
||||||
res = SPIFFS_OK;
|
|
||||||
} else {
|
|
||||||
SPIFFS_CHECK_RES(res);
|
|
||||||
if (ref_pix == cur_pix) {
|
|
||||||
// data page referenced by object index but deleted in lu
|
|
||||||
// copy page to new place and re-write the object index to new place
|
|
||||||
spiffs_page_ix new_pix;
|
|
||||||
res = spiffs_rewrite_page(fs, cur_pix, p_hdr, &new_pix);
|
|
||||||
SPIFFS_CHECK_DBG("LU: FIXUP: data page not found elsewhere, rewriting %04x to new page %04x\n", cur_pix, new_pix);
|
|
||||||
SPIFFS_CHECK_RES(res);
|
|
||||||
*reload_lu = 1;
|
|
||||||
SPIFFS_CHECK_DBG("LU: FIXUP: %04x rewritten to %04x, affected objix_pix %04x\n", cur_pix, new_pix, objix_pix);
|
|
||||||
res = spiffs_rewrite_index(fs, p_hdr->obj_id, p_hdr->span_ix, new_pix, objix_pix);
|
|
||||||
if (res <= _SPIFFS_ERR_CHECK_FIRST && res > _SPIFFS_ERR_CHECK_LAST) {
|
|
||||||
// index bad also, cannot mend this file
|
|
||||||
SPIFFS_CHECK_DBG("LU: FIXUP: index bad %i, cannot mend!\n", res);
|
|
||||||
res = spiffs_page_delete(fs, new_pix);
|
|
||||||
SPIFFS_CHECK_RES(res);
|
|
||||||
res = spiffs_delete_obj_lazy(fs, p_hdr->obj_id);
|
|
||||||
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr->obj_id, 0);
|
|
||||||
} else {
|
|
||||||
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_INDEX, p_hdr->obj_id, p_hdr->span_ix);
|
|
||||||
}
|
|
||||||
SPIFFS_CHECK_RES(res);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// header says index page
|
|
||||||
// index page can be removed if other index with same obj_id and spanix is found
|
|
||||||
res = spiffs_obj_lu_find_id_and_span(fs, p_hdr->obj_id | SPIFFS_OBJ_ID_IX_FLAG, p_hdr->span_ix, cur_pix, 0);
|
|
||||||
if (res == SPIFFS_ERR_NOT_FOUND) {
|
|
||||||
// no such index page found, check for a data page amongst page headers
|
|
||||||
// lu cannot be trusted
|
|
||||||
res = spiffs_obj_lu_find_id_and_span_by_phdr(fs, p_hdr->obj_id | SPIFFS_OBJ_ID_IX_FLAG, 0, 0, 0);
|
|
||||||
if (res == SPIFFS_OK) { // ignore other errors
|
|
||||||
// got a data page also, assume lu corruption only, rewrite to new page
|
|
||||||
spiffs_page_ix new_pix;
|
|
||||||
res = spiffs_rewrite_page(fs, cur_pix, p_hdr, &new_pix);
|
|
||||||
SPIFFS_CHECK_DBG("LU: FIXUP: ix page with data not found elsewhere, rewriting %04x to new page %04x\n", cur_pix, new_pix);
|
|
||||||
SPIFFS_CHECK_RES(res);
|
|
||||||
*reload_lu = 1;
|
|
||||||
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, p_hdr->obj_id, p_hdr->span_ix);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
SPIFFS_CHECK_RES(res);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (lu_obj_id != SPIFFS_OBJ_ID_FREE && lu_obj_id != SPIFFS_OBJ_ID_DELETED) {
|
|
||||||
// look up entry used
|
|
||||||
if ((p_hdr->obj_id | SPIFFS_OBJ_ID_IX_FLAG) != (lu_obj_id | SPIFFS_OBJ_ID_IX_FLAG)) {
|
|
||||||
SPIFFS_CHECK_DBG("LU: pix %04x differ in obj_id lu:%04x ph:%04x\n", cur_pix, lu_obj_id, p_hdr->obj_id);
|
|
||||||
delete_page = 1;
|
|
||||||
if ((p_hdr->flags & SPIFFS_PH_FLAG_DELET) == 0 ||
|
|
||||||
(p_hdr->flags & SPIFFS_PH_FLAG_FINAL) ||
|
|
||||||
(p_hdr->flags & (SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_IXDELE)) == 0) {
|
|
||||||
// page deleted or not finalized, just remove it
|
|
||||||
} else {
|
|
||||||
if (p_hdr->flags & SPIFFS_PH_FLAG_INDEX) {
|
|
||||||
// if data page, check for reference to this page
|
|
||||||
res = spiffs_object_get_data_page_index_reference(fs, p_hdr->obj_id, p_hdr->span_ix, &ref_pix, &objix_pix);
|
|
||||||
if (res == SPIFFS_ERR_NOT_FOUND) {
|
|
||||||
// no object with this id, so remove page safely
|
|
||||||
res = SPIFFS_OK;
|
|
||||||
} else {
|
|
||||||
SPIFFS_CHECK_RES(res);
|
|
||||||
// if found, rewrite page with object id, update index, and delete current
|
|
||||||
if (ref_pix == cur_pix) {
|
|
||||||
spiffs_page_ix new_pix;
|
|
||||||
res = spiffs_rewrite_page(fs, cur_pix, p_hdr, &new_pix);
|
|
||||||
SPIFFS_CHECK_RES(res);
|
|
||||||
res = spiffs_rewrite_index(fs, p_hdr->obj_id, p_hdr->span_ix, new_pix, objix_pix);
|
|
||||||
if (res <= _SPIFFS_ERR_CHECK_FIRST && res > _SPIFFS_ERR_CHECK_LAST) {
|
|
||||||
// index bad also, cannot mend this file
|
|
||||||
SPIFFS_CHECK_DBG("LU: FIXUP: index bad %i, cannot mend!\n", res);
|
|
||||||
res = spiffs_page_delete(fs, new_pix);
|
|
||||||
SPIFFS_CHECK_RES(res);
|
|
||||||
res = spiffs_delete_obj_lazy(fs, p_hdr->obj_id);
|
|
||||||
*reload_lu = 1;
|
|
||||||
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr->obj_id, 0);
|
|
||||||
}
|
|
||||||
SPIFFS_CHECK_RES(res);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// else if index, check for other pages with both obj_id's and spanix
|
|
||||||
spiffs_page_ix objix_pix_lu, objix_pix_ph;
|
|
||||||
// see if other object index page exists for lookup obj id and span index
|
|
||||||
res = spiffs_obj_lu_find_id_and_span(fs, lu_obj_id | SPIFFS_OBJ_ID_IX_FLAG, p_hdr->span_ix, 0, &objix_pix_lu);
|
|
||||||
if (res == SPIFFS_ERR_NOT_FOUND) {
|
|
||||||
res = SPIFFS_OK;
|
|
||||||
objix_pix_lu = 0;
|
|
||||||
}
|
|
||||||
SPIFFS_CHECK_RES(res);
|
|
||||||
// see if other object index exists for page header obj id and span index
|
|
||||||
res = spiffs_obj_lu_find_id_and_span(fs, p_hdr->obj_id | SPIFFS_OBJ_ID_IX_FLAG, p_hdr->span_ix, 0, &objix_pix_ph);
|
|
||||||
if (res == SPIFFS_ERR_NOT_FOUND) {
|
|
||||||
res = SPIFFS_OK;
|
|
||||||
objix_pix_ph = 0;
|
|
||||||
}
|
|
||||||
SPIFFS_CHECK_RES(res);
|
|
||||||
// if both obj_id's found, just delete current
|
|
||||||
if (objix_pix_ph == 0 || objix_pix_lu == 0) {
|
|
||||||
// otherwise try finding first corresponding data pages
|
|
||||||
spiffs_page_ix data_pix_lu, data_pix_ph;
|
|
||||||
// see if other data page exists for look up obj id and span index
|
|
||||||
res = spiffs_obj_lu_find_id_and_span(fs, lu_obj_id & ~SPIFFS_OBJ_ID_IX_FLAG, 0, 0, &data_pix_lu);
|
|
||||||
if (res == SPIFFS_ERR_NOT_FOUND) {
|
|
||||||
res = SPIFFS_OK;
|
|
||||||
objix_pix_lu = 0;
|
|
||||||
}
|
|
||||||
SPIFFS_CHECK_RES(res);
|
|
||||||
// see if other data page exists for page header obj id and span index
|
|
||||||
res = spiffs_obj_lu_find_id_and_span(fs, p_hdr->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG, 0, 0, &data_pix_ph);
|
|
||||||
if (res == SPIFFS_ERR_NOT_FOUND) {
|
|
||||||
res = SPIFFS_OK;
|
|
||||||
objix_pix_ph = 0;
|
|
||||||
}
|
|
||||||
SPIFFS_CHECK_RES(res);
|
|
||||||
|
|
||||||
spiffs_page_header new_ph;
|
|
||||||
new_ph.flags = 0xff & ~(SPIFFS_PH_FLAG_USED | SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_FINAL);
|
|
||||||
new_ph.span_ix = p_hdr->span_ix;
|
|
||||||
spiffs_page_ix new_pix;
|
|
||||||
if ((objix_pix_lu && data_pix_lu && data_pix_ph && objix_pix_ph == 0) ||
|
|
||||||
(objix_pix_lu == 0 && data_pix_ph && objix_pix_ph == 0)) {
|
|
||||||
// got a data page for page header obj id
|
|
||||||
// rewrite as obj_id_ph
|
|
||||||
new_ph.obj_id = p_hdr->obj_id | SPIFFS_OBJ_ID_IX_FLAG;
|
|
||||||
res = spiffs_rewrite_page(fs, cur_pix, &new_ph, &new_pix);
|
|
||||||
SPIFFS_CHECK_DBG("LU: FIXUP: rewrite page %04x as %04x to pix %04x\n", cur_pix, new_ph.obj_id, new_pix);
|
|
||||||
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, p_hdr->obj_id, p_hdr->span_ix);
|
|
||||||
SPIFFS_CHECK_RES(res);
|
|
||||||
*reload_lu = 1;
|
|
||||||
} else if ((objix_pix_ph && data_pix_ph && data_pix_lu && objix_pix_lu == 0) ||
|
|
||||||
(objix_pix_ph == 0 && data_pix_lu && objix_pix_lu == 0)) {
|
|
||||||
// got a data page for look up obj id
|
|
||||||
// rewrite as obj_id_lu
|
|
||||||
new_ph.obj_id = lu_obj_id | SPIFFS_OBJ_ID_IX_FLAG;
|
|
||||||
SPIFFS_CHECK_DBG("LU: FIXUP: rewrite page %04x as %04x\n", cur_pix, new_ph.obj_id);
|
|
||||||
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, p_hdr->obj_id, p_hdr->span_ix);
|
|
||||||
res = spiffs_rewrite_page(fs, cur_pix, &new_ph, &new_pix);
|
|
||||||
SPIFFS_CHECK_RES(res);
|
|
||||||
*reload_lu = 1;
|
|
||||||
} else {
|
|
||||||
// cannot safely do anything
|
|
||||||
SPIFFS_CHECK_DBG("LU: FIXUP: nothing to do, just delete\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (((lu_obj_id & SPIFFS_OBJ_ID_IX_FLAG) && (p_hdr->flags & SPIFFS_PH_FLAG_INDEX)) ||
|
|
||||||
((lu_obj_id & SPIFFS_OBJ_ID_IX_FLAG) == 0 && (p_hdr->flags & SPIFFS_PH_FLAG_INDEX) == 0)) {
|
|
||||||
SPIFFS_CHECK_DBG("LU: %04x lu/page index marking differ\n", cur_pix);
|
|
||||||
spiffs_page_ix data_pix, objix_pix_d;
|
|
||||||
// see if other data page exists for given obj id and span index
|
|
||||||
res = spiffs_obj_lu_find_id_and_span(fs, lu_obj_id & ~SPIFFS_OBJ_ID_IX_FLAG, p_hdr->span_ix, cur_pix, &data_pix);
|
|
||||||
if (res == SPIFFS_ERR_NOT_FOUND) {
|
|
||||||
res = SPIFFS_OK;
|
|
||||||
data_pix = 0;
|
|
||||||
}
|
|
||||||
SPIFFS_CHECK_RES(res);
|
|
||||||
// see if other object index exists for given obj id and span index
|
|
||||||
res = spiffs_obj_lu_find_id_and_span(fs, lu_obj_id | SPIFFS_OBJ_ID_IX_FLAG, p_hdr->span_ix, cur_pix, &objix_pix_d);
|
|
||||||
if (res == SPIFFS_ERR_NOT_FOUND) {
|
|
||||||
res = SPIFFS_OK;
|
|
||||||
objix_pix_d = 0;
|
|
||||||
}
|
|
||||||
SPIFFS_CHECK_RES(res);
|
|
||||||
|
|
||||||
delete_page = 1;
|
|
||||||
// if other data page exists and object index exists, just delete page
|
|
||||||
if (data_pix && objix_pix_d) {
|
|
||||||
SPIFFS_CHECK_DBG("LU: FIXUP: other index and data page exists, simply remove\n");
|
|
||||||
} else
|
|
||||||
// if only data page exists, make this page index
|
|
||||||
if (data_pix && objix_pix_d == 0) {
|
|
||||||
SPIFFS_CHECK_DBG("LU: FIXUP: other data page exists, make this index\n");
|
|
||||||
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_INDEX, lu_obj_id, p_hdr->span_ix);
|
|
||||||
spiffs_page_header new_ph;
|
|
||||||
spiffs_page_ix new_pix;
|
|
||||||
new_ph.flags = 0xff & ~(SPIFFS_PH_FLAG_USED | SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_INDEX);
|
|
||||||
new_ph.obj_id = lu_obj_id | SPIFFS_OBJ_ID_IX_FLAG;
|
|
||||||
new_ph.span_ix = p_hdr->span_ix;
|
|
||||||
res = spiffs_page_allocate_data(fs, new_ph.obj_id, &new_ph, 0, 0, 0, 1, &new_pix);
|
|
||||||
SPIFFS_CHECK_RES(res);
|
|
||||||
res = spiffs_phys_cpy(fs, 0, SPIFFS_PAGE_TO_PADDR(fs, new_pix) + sizeof(spiffs_page_header),
|
|
||||||
SPIFFS_PAGE_TO_PADDR(fs, cur_pix) + sizeof(spiffs_page_header),
|
|
||||||
SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_page_header));
|
|
||||||
SPIFFS_CHECK_RES(res);
|
|
||||||
} else
|
|
||||||
// if only index exists, make data page
|
|
||||||
if (data_pix == 0 && objix_pix_d) {
|
|
||||||
SPIFFS_CHECK_DBG("LU: FIXUP: other index page exists, make this data\n");
|
|
||||||
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, lu_obj_id, p_hdr->span_ix);
|
|
||||||
spiffs_page_header new_ph;
|
|
||||||
spiffs_page_ix new_pix;
|
|
||||||
new_ph.flags = 0xff & ~(SPIFFS_PH_FLAG_USED | SPIFFS_PH_FLAG_FINAL);
|
|
||||||
new_ph.obj_id = lu_obj_id & ~SPIFFS_OBJ_ID_IX_FLAG;
|
|
||||||
new_ph.span_ix = p_hdr->span_ix;
|
|
||||||
res = spiffs_page_allocate_data(fs, new_ph.obj_id, &new_ph, 0, 0, 0, 1, &new_pix);
|
|
||||||
SPIFFS_CHECK_RES(res);
|
|
||||||
res = spiffs_phys_cpy(fs, 0, SPIFFS_PAGE_TO_PADDR(fs, new_pix) + sizeof(spiffs_page_header),
|
|
||||||
SPIFFS_PAGE_TO_PADDR(fs, cur_pix) + sizeof(spiffs_page_header),
|
|
||||||
SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_page_header));
|
|
||||||
SPIFFS_CHECK_RES(res);
|
|
||||||
} else {
|
|
||||||
// if nothing exists, we cannot safely make a decision - delete
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if ((p_hdr->flags & SPIFFS_PH_FLAG_DELET) == 0) {
|
|
||||||
SPIFFS_CHECK_DBG("LU: pix %04x busy in lu but deleted on page\n", cur_pix);
|
|
||||||
delete_page = 1;
|
|
||||||
} else if ((p_hdr->flags & SPIFFS_PH_FLAG_FINAL)) {
|
|
||||||
SPIFFS_CHECK_DBG("LU: pix %04x busy but not final\n", cur_pix);
|
|
||||||
// page can be removed if not referenced by object index
|
|
||||||
*reload_lu = 1;
|
|
||||||
res = spiffs_object_get_data_page_index_reference(fs, lu_obj_id, p_hdr->span_ix, &ref_pix, &objix_pix);
|
|
||||||
if (res == SPIFFS_ERR_NOT_FOUND) {
|
|
||||||
// no object with this id, so remove page safely
|
|
||||||
res = SPIFFS_OK;
|
|
||||||
delete_page = 1;
|
|
||||||
} else {
|
|
||||||
SPIFFS_CHECK_RES(res);
|
|
||||||
if (ref_pix != cur_pix) {
|
|
||||||
SPIFFS_CHECK_DBG("LU: FIXUP: other finalized page is referred, just delete\n");
|
|
||||||
delete_page = 1;
|
|
||||||
} else {
|
|
||||||
// page referenced by object index but not final
|
|
||||||
// just finalize
|
|
||||||
SPIFFS_CHECK_DBG("LU: FIXUP: unfinalized page is referred, finalizing\n");
|
|
||||||
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, p_hdr->obj_id, p_hdr->span_ix);
|
|
||||||
u8_t flags = 0xff & ~SPIFFS_PH_FLAG_FINAL;
|
|
||||||
res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT,
|
|
||||||
0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix) + offsetof(spiffs_page_header, flags),
|
|
||||||
sizeof(u8_t), (u8_t*)&flags);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (delete_page) {
|
|
||||||
SPIFFS_CHECK_DBG("LU: FIXUP: deleting page %04x\n", cur_pix);
|
|
||||||
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_DELETE_PAGE, cur_pix, 0);
|
|
||||||
res = spiffs_page_delete(fs, cur_pix);
|
|
||||||
SPIFFS_CHECK_RES(res);
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
static s32_t spiffs_lookup_check_v(spiffs *fs, spiffs_obj_id obj_id, spiffs_block_ix cur_block, int cur_entry,
|
|
||||||
const void *user_const_p, void *user_var_p) {
|
|
||||||
(void)user_const_p;
|
|
||||||
(void)user_var_p;
|
|
||||||
s32_t res = SPIFFS_OK;
|
|
||||||
spiffs_page_header p_hdr;
|
|
||||||
spiffs_page_ix cur_pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, cur_block, cur_entry);
|
|
||||||
|
|
||||||
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_PROGRESS,
|
|
||||||
(cur_block * 256)/fs->block_count, 0);
|
|
||||||
|
|
||||||
// load header
|
|
||||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
|
|
||||||
0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t*)&p_hdr);
|
|
||||||
SPIFFS_CHECK_RES(res);
|
|
||||||
|
|
||||||
int reload_lu = 0;
|
|
||||||
|
|
||||||
res = spiffs_lookup_check_validate(fs, obj_id, &p_hdr, cur_pix, cur_block, cur_entry, &reload_lu);
|
|
||||||
SPIFFS_CHECK_RES(res);
|
|
||||||
|
|
||||||
if (res == SPIFFS_OK) {
|
|
||||||
return reload_lu ? SPIFFS_VIS_COUNTINUE_RELOAD : SPIFFS_VIS_COUNTINUE;
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Scans all object look up. For each entry, corresponding page header is checked for validity.
|
|
||||||
// If an object index header page is found, this is also checked
|
|
||||||
s32_t spiffs_lookup_consistency_check(spiffs *fs, u8_t check_all_objects) {
|
|
||||||
(void)check_all_objects;
|
|
||||||
s32_t res = SPIFFS_OK;
|
|
||||||
|
|
||||||
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_PROGRESS, 0, 0);
|
|
||||||
|
|
||||||
res = spiffs_obj_lu_find_entry_visitor(fs, 0, 0, 0, 0, spiffs_lookup_check_v, 0, 0, 0, 0);
|
|
||||||
|
|
||||||
if (res == SPIFFS_VIS_END) {
|
|
||||||
res = SPIFFS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (res != SPIFFS_OK) {
|
|
||||||
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_ERROR, res, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_PROGRESS, 256, 0);
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
//---------------------------------------
|
|
||||||
// Page consistency
|
|
||||||
|
|
||||||
// Scans all pages (except lu pages), reserves 4 bits in working memory for each page
|
|
||||||
// bit 0: 0 == FREE|DELETED, 1 == USED
|
|
||||||
// bit 1: 0 == UNREFERENCED, 1 == REFERENCED
|
|
||||||
// bit 2: 0 == NOT_INDEX, 1 == INDEX
|
|
||||||
// bit 3: unused
|
|
||||||
// A consistent file system will have only pages being
|
|
||||||
// * x000 free, unreferenced, not index
|
|
||||||
// * x011 used, referenced only once, not index
|
|
||||||
// * x101 used, unreferenced, index
|
|
||||||
// The working memory might not fit all pages so several scans might be needed
|
|
||||||
static s32_t spiffs_page_consistency_check_i(spiffs *fs) {
|
|
||||||
const u32_t bits = 4;
|
|
||||||
const spiffs_page_ix pages_per_scan = SPIFFS_CFG_LOG_PAGE_SZ(fs) * 8 / bits;
|
|
||||||
|
|
||||||
s32_t res = SPIFFS_OK;
|
|
||||||
spiffs_page_ix pix_offset = 0;
|
|
||||||
|
|
||||||
// for each range of pages fitting into work memory
|
|
||||||
while (pix_offset < SPIFFS_PAGES_PER_BLOCK(fs) * fs->block_count) {
|
|
||||||
// set this flag to abort all checks and rescan the page range
|
|
||||||
u8_t restart = 0;
|
|
||||||
memset(fs->work, 0, SPIFFS_CFG_LOG_PAGE_SZ(fs));
|
|
||||||
|
|
||||||
spiffs_block_ix cur_block = 0;
|
|
||||||
// build consistency bitmap for id range traversing all blocks
|
|
||||||
while (!restart && cur_block < fs->block_count) {
|
|
||||||
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_PROGRESS,
|
|
||||||
(pix_offset*256)/(SPIFFS_PAGES_PER_BLOCK(fs) * fs->block_count) +
|
|
||||||
((((cur_block * pages_per_scan * 256)/ (SPIFFS_PAGES_PER_BLOCK(fs) * fs->block_count))) / fs->block_count),
|
|
||||||
0);
|
|
||||||
// traverse each page except for lookup pages
|
|
||||||
spiffs_page_ix cur_pix = SPIFFS_OBJ_LOOKUP_PAGES(fs) + SPIFFS_PAGES_PER_BLOCK(fs) * cur_block;
|
|
||||||
while (!restart && cur_pix < SPIFFS_PAGES_PER_BLOCK(fs) * (cur_block+1)) {
|
|
||||||
//if ((cur_pix & 0xff) == 0)
|
|
||||||
// SPIFFS_CHECK_DBG("PA: processing pix %08x, block %08x of pix %08x, block %08x\n",
|
|
||||||
// cur_pix, cur_block, SPIFFS_PAGES_PER_BLOCK(fs) * fs->block_count, fs->block_count);
|
|
||||||
|
|
||||||
// read header
|
|
||||||
spiffs_page_header p_hdr;
|
|
||||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
|
|
||||||
0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t*)&p_hdr);
|
|
||||||
SPIFFS_CHECK_RES(res);
|
|
||||||
|
|
||||||
u8_t within_range = (cur_pix >= pix_offset && cur_pix < pix_offset + pages_per_scan);
|
|
||||||
const u32_t pix_byte_ix = (cur_pix - pix_offset) / (8/bits);
|
|
||||||
const u8_t pix_bit_ix = (cur_pix & ((8/bits)-1)) * bits;
|
|
||||||
|
|
||||||
if (within_range &&
|
|
||||||
(p_hdr.flags & SPIFFS_PH_FLAG_DELET) && (p_hdr.flags & SPIFFS_PH_FLAG_USED) == 0) {
|
|
||||||
// used
|
|
||||||
fs->work[pix_byte_ix] |= (1<<(pix_bit_ix + 0));
|
|
||||||
}
|
|
||||||
if ((p_hdr.flags & SPIFFS_PH_FLAG_DELET) &&
|
|
||||||
(p_hdr.flags & SPIFFS_PH_FLAG_IXDELE) &&
|
|
||||||
(p_hdr.flags & (SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_USED)) == 0) {
|
|
||||||
// found non-deleted index
|
|
||||||
if (within_range) {
|
|
||||||
fs->work[pix_byte_ix] |= (1<<(pix_bit_ix + 2));
|
|
||||||
}
|
|
||||||
|
|
||||||
// load non-deleted index
|
|
||||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
|
|
||||||
0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);
|
|
||||||
SPIFFS_CHECK_RES(res);
|
|
||||||
|
|
||||||
// traverse index for referenced pages
|
|
||||||
spiffs_page_ix *object_page_index;
|
|
||||||
spiffs_page_header *objix_p_hdr = (spiffs_page_header *)fs->lu_work;
|
|
||||||
|
|
||||||
int entries;
|
|
||||||
int i;
|
|
||||||
spiffs_span_ix data_spix_offset;
|
|
||||||
if (p_hdr.span_ix == 0) {
|
|
||||||
// object header page index
|
|
||||||
entries = SPIFFS_OBJ_HDR_IX_LEN(fs);
|
|
||||||
data_spix_offset = 0;
|
|
||||||
object_page_index = (spiffs_page_ix *)((u8_t *)fs->lu_work + sizeof(spiffs_page_object_ix_header));
|
|
||||||
} else {
|
|
||||||
// object page index
|
|
||||||
entries = SPIFFS_OBJ_IX_LEN(fs);
|
|
||||||
data_spix_offset = SPIFFS_OBJ_HDR_IX_LEN(fs) + SPIFFS_OBJ_IX_LEN(fs) * (p_hdr.span_ix - 1);
|
|
||||||
object_page_index = (spiffs_page_ix *)((u8_t *)fs->lu_work + sizeof(spiffs_page_object_ix));
|
|
||||||
}
|
|
||||||
|
|
||||||
// for all entries in index
|
|
||||||
for (i = 0; !restart && i < entries; i++) {
|
|
||||||
spiffs_page_ix rpix = object_page_index[i];
|
|
||||||
u8_t rpix_within_range = rpix >= pix_offset && rpix < pix_offset + pages_per_scan;
|
|
||||||
|
|
||||||
if ((rpix != (spiffs_page_ix)-1 && rpix > SPIFFS_MAX_PAGES(fs))
|
|
||||||
|| (rpix_within_range && SPIFFS_IS_LOOKUP_PAGE(fs, rpix))) {
|
|
||||||
|
|
||||||
// bad reference
|
|
||||||
SPIFFS_CHECK_DBG("PA: pix %04x bad pix / LU referenced from page %04x\n",
|
|
||||||
rpix, cur_pix);
|
|
||||||
// check for data page elsewhere
|
|
||||||
spiffs_page_ix data_pix;
|
|
||||||
res = spiffs_obj_lu_find_id_and_span(fs, objix_p_hdr->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG,
|
|
||||||
data_spix_offset + i, 0, &data_pix);
|
|
||||||
if (res == SPIFFS_ERR_NOT_FOUND) {
|
|
||||||
res = SPIFFS_OK;
|
|
||||||
data_pix = 0;
|
|
||||||
}
|
|
||||||
SPIFFS_CHECK_RES(res);
|
|
||||||
if (data_pix == 0) {
|
|
||||||
// if not, allocate free page
|
|
||||||
spiffs_page_header new_ph;
|
|
||||||
new_ph.flags = 0xff & ~(SPIFFS_PH_FLAG_USED | SPIFFS_PH_FLAG_FINAL);
|
|
||||||
new_ph.obj_id = objix_p_hdr->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG;
|
|
||||||
new_ph.span_ix = data_spix_offset + i;
|
|
||||||
res = spiffs_page_allocate_data(fs, new_ph.obj_id, &new_ph, 0, 0, 0, 1, &data_pix);
|
|
||||||
SPIFFS_CHECK_RES(res);
|
|
||||||
SPIFFS_CHECK_DBG("PA: FIXUP: found no existing data page, created new @ %04x\n", data_pix);
|
|
||||||
}
|
|
||||||
// remap index
|
|
||||||
SPIFFS_CHECK_DBG("PA: FIXUP: rewriting index pix %04x\n", cur_pix);
|
|
||||||
res = spiffs_rewrite_index(fs, objix_p_hdr->obj_id | SPIFFS_OBJ_ID_IX_FLAG,
|
|
||||||
data_spix_offset + i, data_pix, cur_pix);
|
|
||||||
if (res <= _SPIFFS_ERR_CHECK_FIRST && res > _SPIFFS_ERR_CHECK_LAST) {
|
|
||||||
// index bad also, cannot mend this file
|
|
||||||
SPIFFS_CHECK_DBG("PA: FIXUP: index bad %i, cannot mend - delete object\n", res);
|
|
||||||
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, objix_p_hdr->obj_id, 0);
|
|
||||||
// delete file
|
|
||||||
res = spiffs_page_delete(fs, cur_pix);
|
|
||||||
} else {
|
|
||||||
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_FIX_INDEX, objix_p_hdr->obj_id, objix_p_hdr->span_ix);
|
|
||||||
}
|
|
||||||
SPIFFS_CHECK_RES(res);
|
|
||||||
restart = 1;
|
|
||||||
|
|
||||||
} else if (rpix_within_range) {
|
|
||||||
|
|
||||||
// valid reference
|
|
||||||
// read referenced page header
|
|
||||||
spiffs_page_header rp_hdr;
|
|
||||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
|
|
||||||
0, SPIFFS_PAGE_TO_PADDR(fs, rpix), sizeof(spiffs_page_header), (u8_t*)&rp_hdr);
|
|
||||||
SPIFFS_CHECK_RES(res);
|
|
||||||
|
|
||||||
// cross reference page header check
|
|
||||||
if (rp_hdr.obj_id != (p_hdr.obj_id & ~SPIFFS_OBJ_ID_IX_FLAG) ||
|
|
||||||
rp_hdr.span_ix != data_spix_offset + i ||
|
|
||||||
(rp_hdr.flags & (SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_USED)) !=
|
|
||||||
(SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_INDEX)) {
|
|
||||||
SPIFFS_CHECK_DBG("PA: pix %04x has inconsistent page header ix id/span:%04x/%04x, ref id/span:%04x/%04x flags:%02x\n",
|
|
||||||
rpix, p_hdr.obj_id & ~SPIFFS_OBJ_ID_IX_FLAG, data_spix_offset + i,
|
|
||||||
rp_hdr.obj_id, rp_hdr.span_ix, rp_hdr.flags);
|
|
||||||
// try finding correct page
|
|
||||||
spiffs_page_ix data_pix;
|
|
||||||
res = spiffs_obj_lu_find_id_and_span(fs, p_hdr.obj_id & ~SPIFFS_OBJ_ID_IX_FLAG,
|
|
||||||
data_spix_offset + i, rpix, &data_pix);
|
|
||||||
if (res == SPIFFS_ERR_NOT_FOUND) {
|
|
||||||
res = SPIFFS_OK;
|
|
||||||
data_pix = 0;
|
|
||||||
}
|
|
||||||
SPIFFS_CHECK_RES(res);
|
|
||||||
if (data_pix == 0) {
|
|
||||||
// not found, this index is badly borked
|
|
||||||
SPIFFS_CHECK_DBG("PA: FIXUP: index bad, delete object id %04x\n", p_hdr.obj_id);
|
|
||||||
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr.obj_id, 0);
|
|
||||||
res = spiffs_delete_obj_lazy(fs, p_hdr.obj_id);
|
|
||||||
SPIFFS_CHECK_RES(res);
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
// found it, so rewrite index
|
|
||||||
SPIFFS_CHECK_DBG("PA: FIXUP: found correct data pix %04x, rewrite ix pix %04x id %04x\n",
|
|
||||||
data_pix, cur_pix, p_hdr.obj_id);
|
|
||||||
res = spiffs_rewrite_index(fs, p_hdr.obj_id, data_spix_offset + i, data_pix, cur_pix);
|
|
||||||
if (res <= _SPIFFS_ERR_CHECK_FIRST && res > _SPIFFS_ERR_CHECK_LAST) {
|
|
||||||
// index bad also, cannot mend this file
|
|
||||||
SPIFFS_CHECK_DBG("PA: FIXUP: index bad %i, cannot mend!\n", res);
|
|
||||||
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr.obj_id, 0);
|
|
||||||
res = spiffs_delete_obj_lazy(fs, p_hdr.obj_id);
|
|
||||||
} else {
|
|
||||||
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_FIX_INDEX, p_hdr.obj_id, p_hdr.span_ix);
|
|
||||||
}
|
|
||||||
SPIFFS_CHECK_RES(res);
|
|
||||||
restart = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// mark rpix as referenced
|
|
||||||
const u32_t rpix_byte_ix = (rpix - pix_offset) / (8/bits);
|
|
||||||
const u8_t rpix_bit_ix = (rpix & ((8/bits)-1)) * bits;
|
|
||||||
if (fs->work[rpix_byte_ix] & (1<<(rpix_bit_ix + 1))) {
|
|
||||||
SPIFFS_CHECK_DBG("PA: pix %04x multiple referenced from page %04x\n",
|
|
||||||
rpix, cur_pix);
|
|
||||||
// Here, we should have fixed all broken references - getting this means there
|
|
||||||
// must be multiple files with same object id. Only solution is to delete
|
|
||||||
// the object which is referring to this page
|
|
||||||
SPIFFS_CHECK_DBG("PA: FIXUP: removing object %04x and page %04x\n",
|
|
||||||
p_hdr.obj_id, cur_pix);
|
|
||||||
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr.obj_id, 0);
|
|
||||||
res = spiffs_delete_obj_lazy(fs, p_hdr.obj_id);
|
|
||||||
SPIFFS_CHECK_RES(res);
|
|
||||||
// extra precaution, delete this page also
|
|
||||||
res = spiffs_page_delete(fs, cur_pix);
|
|
||||||
SPIFFS_CHECK_RES(res);
|
|
||||||
restart = 1;
|
|
||||||
}
|
|
||||||
fs->work[rpix_byte_ix] |= (1<<(rpix_bit_ix + 1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} // for all index entries
|
|
||||||
} // found index
|
|
||||||
|
|
||||||
// next page
|
|
||||||
cur_pix++;
|
|
||||||
}
|
|
||||||
// next block
|
|
||||||
cur_block++;
|
|
||||||
}
|
|
||||||
// check consistency bitmap
|
|
||||||
if (!restart) {
|
|
||||||
spiffs_page_ix objix_pix;
|
|
||||||
spiffs_page_ix rpix;
|
|
||||||
|
|
||||||
u32_t byte_ix;
|
|
||||||
u8_t bit_ix;
|
|
||||||
for (byte_ix = 0; !restart && byte_ix < SPIFFS_CFG_LOG_PAGE_SZ(fs); byte_ix++) {
|
|
||||||
for (bit_ix = 0; !restart && bit_ix < 8/bits; bit_ix ++) {
|
|
||||||
u8_t bitmask = (fs->work[byte_ix] >> (bit_ix * bits)) & 0x7;
|
|
||||||
spiffs_page_ix cur_pix = pix_offset + byte_ix * (8/bits) + bit_ix;
|
|
||||||
|
|
||||||
// 000 ok - free, unreferenced, not index
|
|
||||||
|
|
||||||
if (bitmask == 0x1) {
|
|
||||||
|
|
||||||
// 001
|
|
||||||
SPIFFS_CHECK_DBG("PA: pix %04x USED, UNREFERENCED, not index\n", cur_pix);
|
|
||||||
|
|
||||||
u8_t rewrite_ix_to_this = 0;
|
|
||||||
u8_t delete_page = 0;
|
|
||||||
// check corresponding object index entry
|
|
||||||
spiffs_page_header p_hdr;
|
|
||||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
|
|
||||||
0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t*)&p_hdr);
|
|
||||||
SPIFFS_CHECK_RES(res);
|
|
||||||
|
|
||||||
res = spiffs_object_get_data_page_index_reference(fs, p_hdr.obj_id, p_hdr.span_ix,
|
|
||||||
&rpix, &objix_pix);
|
|
||||||
if (res == SPIFFS_OK) {
|
|
||||||
if (((rpix == (spiffs_page_ix)-1 || rpix > SPIFFS_MAX_PAGES(fs)) || (SPIFFS_IS_LOOKUP_PAGE(fs, rpix)))) {
|
|
||||||
// pointing to a bad page altogether, rewrite index to this
|
|
||||||
rewrite_ix_to_this = 1;
|
|
||||||
SPIFFS_CHECK_DBG("PA: corresponding ref is bad: %04x, rewrite to this %04x\n", rpix, cur_pix);
|
|
||||||
} else {
|
|
||||||
// pointing to something else, check what
|
|
||||||
spiffs_page_header rp_hdr;
|
|
||||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
|
|
||||||
0, SPIFFS_PAGE_TO_PADDR(fs, rpix), sizeof(spiffs_page_header), (u8_t*)&rp_hdr);
|
|
||||||
SPIFFS_CHECK_RES(res);
|
|
||||||
if (((p_hdr.obj_id & ~SPIFFS_OBJ_ID_IX_FLAG) == rp_hdr.obj_id) &&
|
|
||||||
((rp_hdr.flags & (SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_USED | SPIFFS_PH_FLAG_FINAL)) ==
|
|
||||||
(SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_DELET))) {
|
|
||||||
// pointing to something else valid, just delete this page then
|
|
||||||
SPIFFS_CHECK_DBG("PA: corresponding ref is good but different: %04x, delete this %04x\n", rpix, cur_pix);
|
|
||||||
delete_page = 1;
|
|
||||||
} else {
|
|
||||||
// pointing to something weird, update index to point to this page instead
|
|
||||||
if (rpix != cur_pix) {
|
|
||||||
SPIFFS_CHECK_DBG("PA: corresponding ref is weird: %04x %s%s%s%s, rewrite this %04x\n", rpix,
|
|
||||||
(rp_hdr.flags & SPIFFS_PH_FLAG_INDEX) ? "" : "INDEX ",
|
|
||||||
(rp_hdr.flags & SPIFFS_PH_FLAG_DELET) ? "" : "DELETED ",
|
|
||||||
(rp_hdr.flags & SPIFFS_PH_FLAG_USED) ? "NOTUSED " : "",
|
|
||||||
(rp_hdr.flags & SPIFFS_PH_FLAG_FINAL) ? "NOTFINAL " : "",
|
|
||||||
cur_pix);
|
|
||||||
rewrite_ix_to_this = 1;
|
|
||||||
} else {
|
|
||||||
// should not happen, destined for fubar
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (res == SPIFFS_ERR_NOT_FOUND) {
|
|
||||||
SPIFFS_CHECK_DBG("PA: corresponding ref not found, delete %04x\n", cur_pix);
|
|
||||||
delete_page = 1;
|
|
||||||
res = SPIFFS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rewrite_ix_to_this) {
|
|
||||||
// if pointing to invalid page, redirect index to this page
|
|
||||||
SPIFFS_CHECK_DBG("PA: FIXUP: rewrite index id %04x data spix %04x to point to this pix: %04x\n",
|
|
||||||
p_hdr.obj_id, p_hdr.span_ix, cur_pix);
|
|
||||||
res = spiffs_rewrite_index(fs, p_hdr.obj_id, p_hdr.span_ix, cur_pix, objix_pix);
|
|
||||||
if (res <= _SPIFFS_ERR_CHECK_FIRST && res > _SPIFFS_ERR_CHECK_LAST) {
|
|
||||||
// index bad also, cannot mend this file
|
|
||||||
SPIFFS_CHECK_DBG("PA: FIXUP: index bad %i, cannot mend!\n", res);
|
|
||||||
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr.obj_id, 0);
|
|
||||||
res = spiffs_page_delete(fs, cur_pix);
|
|
||||||
SPIFFS_CHECK_RES(res);
|
|
||||||
res = spiffs_delete_obj_lazy(fs, p_hdr.obj_id);
|
|
||||||
} else {
|
|
||||||
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_FIX_INDEX, p_hdr.obj_id, p_hdr.span_ix);
|
|
||||||
}
|
|
||||||
SPIFFS_CHECK_RES(res);
|
|
||||||
restart = 1;
|
|
||||||
continue;
|
|
||||||
} else if (delete_page) {
|
|
||||||
SPIFFS_CHECK_DBG("PA: FIXUP: deleting page %04x\n", cur_pix);
|
|
||||||
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_PAGE, cur_pix, 0);
|
|
||||||
res = spiffs_page_delete(fs, cur_pix);
|
|
||||||
}
|
|
||||||
SPIFFS_CHECK_RES(res);
|
|
||||||
}
|
|
||||||
if (bitmask == 0x2) {
|
|
||||||
|
|
||||||
// 010
|
|
||||||
SPIFFS_CHECK_DBG("PA: pix %04x FREE, REFERENCED, not index\n", cur_pix);
|
|
||||||
|
|
||||||
// no op, this should be taken care of when checking valid references
|
|
||||||
}
|
|
||||||
|
|
||||||
// 011 ok - busy, referenced, not index
|
|
||||||
|
|
||||||
if (bitmask == 0x4) {
|
|
||||||
|
|
||||||
// 100
|
|
||||||
SPIFFS_CHECK_DBG("PA: pix %04x FREE, unreferenced, INDEX\n", cur_pix);
|
|
||||||
|
|
||||||
// this should never happen, major fubar
|
|
||||||
}
|
|
||||||
|
|
||||||
// 101 ok - busy, unreferenced, index
|
|
||||||
|
|
||||||
if (bitmask == 0x6) {
|
|
||||||
|
|
||||||
// 110
|
|
||||||
SPIFFS_CHECK_DBG("PA: pix %04x FREE, REFERENCED, INDEX\n", cur_pix);
|
|
||||||
|
|
||||||
// no op, this should be taken care of when checking valid references
|
|
||||||
}
|
|
||||||
if (bitmask == 0x7) {
|
|
||||||
|
|
||||||
// 111
|
|
||||||
SPIFFS_CHECK_DBG("PA: pix %04x USED, REFERENCED, INDEX\n", cur_pix);
|
|
||||||
|
|
||||||
// no op, this should be taken care of when checking valid references
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SPIFFS_CHECK_DBG("PA: processed %04x, restart %i\n", pix_offset, restart);
|
|
||||||
// next page range
|
|
||||||
if (!restart) {
|
|
||||||
pix_offset += pages_per_scan;
|
|
||||||
}
|
|
||||||
} // while page range not reached end
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Checks consistency amongst all pages and fixes irregularities
|
|
||||||
s32_t spiffs_page_consistency_check(spiffs *fs) {
|
|
||||||
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_PROGRESS, 0, 0);
|
|
||||||
s32_t res = spiffs_page_consistency_check_i(fs);
|
|
||||||
if (res != SPIFFS_OK) {
|
|
||||||
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_ERROR, res, 0);
|
|
||||||
}
|
|
||||||
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_PROGRESS, 256, 0);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
//---------------------------------------
|
|
||||||
// Object index consistency
|
|
||||||
|
|
||||||
// searches for given object id in temporary object id index,
|
|
||||||
// returns the index or -1
|
|
||||||
static int spiffs_object_index_search(spiffs *fs, spiffs_obj_id obj_id) {
|
|
||||||
u32_t i;
|
|
||||||
spiffs_obj_id *obj_table = (spiffs_obj_id *)fs->work;
|
|
||||||
obj_id &= ~SPIFFS_OBJ_ID_IX_FLAG;
|
|
||||||
for (i = 0; i < SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id); i++) {
|
|
||||||
if ((obj_table[i] & ~SPIFFS_OBJ_ID_IX_FLAG) == obj_id) {
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static s32_t spiffs_object_index_consistency_check_v(spiffs *fs, spiffs_obj_id obj_id, spiffs_block_ix cur_block,
|
|
||||||
int cur_entry, const void *user_const_p, void *user_var_p) {
|
|
||||||
(void)user_const_p;
|
|
||||||
s32_t res_c = SPIFFS_VIS_COUNTINUE;
|
|
||||||
s32_t res = SPIFFS_OK;
|
|
||||||
u32_t *log_ix = (u32_t*)user_var_p;
|
|
||||||
spiffs_obj_id *obj_table = (spiffs_obj_id *)fs->work;
|
|
||||||
|
|
||||||
CHECK_CB(fs, SPIFFS_CHECK_INDEX, SPIFFS_CHECK_PROGRESS,
|
|
||||||
(cur_block * 256)/fs->block_count, 0);
|
|
||||||
|
|
||||||
if (obj_id != SPIFFS_OBJ_ID_FREE && obj_id != SPIFFS_OBJ_ID_DELETED && (obj_id & SPIFFS_OBJ_ID_IX_FLAG)) {
|
|
||||||
spiffs_page_header p_hdr;
|
|
||||||
spiffs_page_ix cur_pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, cur_block, cur_entry);
|
|
||||||
|
|
||||||
// load header
|
|
||||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
|
|
||||||
0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t*)&p_hdr);
|
|
||||||
SPIFFS_CHECK_RES(res);
|
|
||||||
|
|
||||||
if (p_hdr.span_ix == 0 &&
|
|
||||||
(p_hdr.flags & (SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_IXDELE)) ==
|
|
||||||
(SPIFFS_PH_FLAG_DELET)) {
|
|
||||||
SPIFFS_CHECK_DBG("IX: pix %04x, obj id:%04x spix:%04x header not fully deleted - deleting\n",
|
|
||||||
cur_pix, obj_id, p_hdr.span_ix);
|
|
||||||
CHECK_CB(fs, SPIFFS_CHECK_INDEX, SPIFFS_CHECK_DELETE_PAGE, cur_pix, obj_id);
|
|
||||||
res = spiffs_page_delete(fs, cur_pix);
|
|
||||||
SPIFFS_CHECK_RES(res);
|
|
||||||
return res_c;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((p_hdr.flags & (SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_IXDELE)) ==
|
|
||||||
(SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_IXDELE)) {
|
|
||||||
return res_c;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (p_hdr.span_ix == 0) {
|
|
||||||
// objix header page, register objid as reachable
|
|
||||||
int r = spiffs_object_index_search(fs, obj_id);
|
|
||||||
if (r == -1) {
|
|
||||||
// not registered, do it
|
|
||||||
obj_table[*log_ix] = obj_id & ~SPIFFS_OBJ_ID_IX_FLAG;
|
|
||||||
(*log_ix)++;
|
|
||||||
if (*log_ix >= SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id)) {
|
|
||||||
*log_ix = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else { // span index
|
|
||||||
// objix page, see if header can be found
|
|
||||||
int r = spiffs_object_index_search(fs, obj_id);
|
|
||||||
u8_t delete = 0;
|
|
||||||
if (r == -1) {
|
|
||||||
// not in temporary index, try finding it
|
|
||||||
spiffs_page_ix objix_hdr_pix;
|
|
||||||
res = spiffs_obj_lu_find_id_and_span(fs, obj_id | SPIFFS_OBJ_ID_IX_FLAG, 0, 0, &objix_hdr_pix);
|
|
||||||
res_c = SPIFFS_VIS_COUNTINUE_RELOAD;
|
|
||||||
if (res == SPIFFS_OK) {
|
|
||||||
// found, register as reachable
|
|
||||||
obj_table[*log_ix] = obj_id & ~SPIFFS_OBJ_ID_IX_FLAG;
|
|
||||||
} else if (res == SPIFFS_ERR_NOT_FOUND) {
|
|
||||||
// not found, register as unreachable
|
|
||||||
delete = 1;
|
|
||||||
obj_table[*log_ix] = obj_id | SPIFFS_OBJ_ID_IX_FLAG;
|
|
||||||
} else {
|
|
||||||
SPIFFS_CHECK_RES(res);
|
|
||||||
}
|
|
||||||
(*log_ix)++;
|
|
||||||
if (*log_ix >= SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id)) {
|
|
||||||
*log_ix = 0;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// in temporary index, check reachable flag
|
|
||||||
if ((obj_table[r] & SPIFFS_OBJ_ID_IX_FLAG)) {
|
|
||||||
// registered as unreachable
|
|
||||||
delete = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (delete) {
|
|
||||||
SPIFFS_CHECK_DBG("IX: FIXUP: pix %04x, obj id:%04x spix:%04x is orphan index - deleting\n",
|
|
||||||
cur_pix, obj_id, p_hdr.span_ix);
|
|
||||||
CHECK_CB(fs, SPIFFS_CHECK_INDEX, SPIFFS_CHECK_DELETE_ORPHANED_INDEX, cur_pix, obj_id);
|
|
||||||
res = spiffs_page_delete(fs, cur_pix);
|
|
||||||
SPIFFS_CHECK_RES(res);
|
|
||||||
}
|
|
||||||
} // span index
|
|
||||||
} // valid object index id
|
|
||||||
|
|
||||||
return res_c;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Removes orphaned and partially deleted index pages.
|
|
||||||
// Scans for index pages. When an index page is found, corresponding index header is searched for.
|
|
||||||
// If no such page exists, the index page cannot be reached as no index header exists and must be
|
|
||||||
// deleted.
|
|
||||||
s32_t spiffs_object_index_consistency_check(spiffs *fs) {
|
|
||||||
s32_t res = SPIFFS_OK;
|
|
||||||
// impl note:
|
|
||||||
// fs->work is used for a temporary object index memory, listing found object ids and
|
|
||||||
// indicating whether they can be reached or not. Acting as a fifo if object ids cannot fit.
|
|
||||||
// In the temporary object index memory, SPIFFS_OBJ_ID_IX_FLAG bit is used to indicate
|
|
||||||
// a reachable/unreachable object id.
|
|
||||||
memset(fs->work, 0, SPIFFS_CFG_LOG_PAGE_SZ(fs));
|
|
||||||
u32_t obj_id_log_ix = 0;
|
|
||||||
CHECK_CB(fs, SPIFFS_CHECK_INDEX, SPIFFS_CHECK_PROGRESS, 0, 0);
|
|
||||||
res = spiffs_obj_lu_find_entry_visitor(fs, 0, 0, 0, 0, spiffs_object_index_consistency_check_v, &obj_id_log_ix,
|
|
||||||
0, 0, 0);
|
|
||||||
if (res == SPIFFS_VIS_END) {
|
|
||||||
res = SPIFFS_OK;
|
|
||||||
}
|
|
||||||
if (res != SPIFFS_OK) {
|
|
||||||
CHECK_CB(fs, SPIFFS_CHECK_INDEX, SPIFFS_CHECK_ERROR, res, 0);
|
|
||||||
}
|
|
||||||
CHECK_CB(fs, SPIFFS_CHECK_INDEX, SPIFFS_CHECK_PROGRESS, 256, 0);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // !SPIFFS_READ_ONLY
|
|
||||||
@@ -1,253 +0,0 @@
|
|||||||
/*
|
|
||||||
* spiffs_config.h
|
|
||||||
*
|
|
||||||
* Created on: Jul 3, 2013
|
|
||||||
* Author: petera
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef SPIFFS_CONFIG_H_
|
|
||||||
#define SPIFFS_CONFIG_H_
|
|
||||||
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#define c_memcpy memcpy
|
|
||||||
#define c_printf printf
|
|
||||||
#define c_memset memset
|
|
||||||
|
|
||||||
typedef int16_t file_t;
|
|
||||||
typedef int32_t s32_t;
|
|
||||||
typedef uint32_t u32_t;
|
|
||||||
typedef int16_t s16_t;
|
|
||||||
typedef uint16_t u16_t;
|
|
||||||
typedef int8_t s8_t;
|
|
||||||
typedef uint8_t u8_t;
|
|
||||||
|
|
||||||
#ifndef SEEK_SET
|
|
||||||
#define SEEK_SET 0 /* set file offset to offset */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef SEEK_CUR
|
|
||||||
#define SEEK_CUR 1 /* set file offset to current plus offset */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef SEEK_END
|
|
||||||
#define SEEK_END 2 /* set file offset to EOF plus offset */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef EOF
|
|
||||||
#define EOF (-1)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// compile time switches
|
|
||||||
|
|
||||||
// Set generic spiffs debug output call.
|
|
||||||
#ifndef SPIFFS_DBG
|
|
||||||
#define SPIFFS_DBG(...) //printf(__VA_ARGS__)
|
|
||||||
#endif
|
|
||||||
// Set spiffs debug output call for garbage collecting.
|
|
||||||
#ifndef SPIFFS_GC_DBG
|
|
||||||
#define SPIFFS_GC_DBG(...) //printf(__VA_ARGS__)
|
|
||||||
#endif
|
|
||||||
// Set spiffs debug output call for caching.
|
|
||||||
#ifndef SPIFFS_CACHE_DBG
|
|
||||||
#define SPIFFS_CACHE_DBG(...) //printf(__VA_ARGS__)
|
|
||||||
#endif
|
|
||||||
// Set spiffs debug output call for system consistency checks.
|
|
||||||
#ifndef SPIFFS_CHECK_DBG
|
|
||||||
#define SPIFFS_CHECK_DBG(...) //printf(__VA_ARGS__)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Enable/disable API functions to determine exact number of bytes
|
|
||||||
// for filedescriptor and cache buffers. Once decided for a configuration,
|
|
||||||
// this can be disabled to reduce flash.
|
|
||||||
#ifndef SPIFFS_BUFFER_HELP
|
|
||||||
#define SPIFFS_BUFFER_HELP 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Enables/disable memory read caching of nucleus file system operations.
|
|
||||||
// If enabled, memory area must be provided for cache in SPIFFS_mount.
|
|
||||||
#ifndef SPIFFS_CACHE
|
|
||||||
#define SPIFFS_CACHE 1
|
|
||||||
#endif
|
|
||||||
#if SPIFFS_CACHE
|
|
||||||
// Enables memory write caching for file descriptors in hydrogen
|
|
||||||
#ifndef SPIFFS_CACHE_WR
|
|
||||||
#define SPIFFS_CACHE_WR 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Enable/disable statistics on caching. Debug/test purpose only.
|
|
||||||
#ifndef SPIFFS_CACHE_STATS
|
|
||||||
#define SPIFFS_CACHE_STATS 0
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Always check header of each accessed page to ensure consistent state.
|
|
||||||
// If enabled it will increase number of reads, will increase flash.
|
|
||||||
#ifndef SPIFFS_PAGE_CHECK
|
|
||||||
#define SPIFFS_PAGE_CHECK 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Define maximum number of gc runs to perform to reach desired free pages.
|
|
||||||
#ifndef SPIFFS_GC_MAX_RUNS
|
|
||||||
#define SPIFFS_GC_MAX_RUNS 5
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Enable/disable statistics on gc. Debug/test purpose only.
|
|
||||||
#ifndef SPIFFS_GC_STATS
|
|
||||||
#define SPIFFS_GC_STATS 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Garbage collecting examines all pages in a block which and sums up
|
|
||||||
// to a block score. Deleted pages normally gives positive score and
|
|
||||||
// used pages normally gives a negative score (as these must be moved).
|
|
||||||
// To have a fair wear-leveling, the erase age is also included in score,
|
|
||||||
// whose factor normally is the most positive.
|
|
||||||
// The larger the score, the more likely it is that the block will
|
|
||||||
// picked for garbage collection.
|
|
||||||
|
|
||||||
// Garbage collecting heuristics - weight used for deleted pages.
|
|
||||||
#ifndef SPIFFS_GC_HEUR_W_DELET
|
|
||||||
#define SPIFFS_GC_HEUR_W_DELET (5)
|
|
||||||
#endif
|
|
||||||
// Garbage collecting heuristics - weight used for used pages.
|
|
||||||
#ifndef SPIFFS_GC_HEUR_W_USED
|
|
||||||
#define SPIFFS_GC_HEUR_W_USED (-1)
|
|
||||||
#endif
|
|
||||||
// Garbage collecting heuristics - weight used for time between
|
|
||||||
// last erased and erase of this block.
|
|
||||||
#ifndef SPIFFS_GC_HEUR_W_ERASE_AGE
|
|
||||||
#define SPIFFS_GC_HEUR_W_ERASE_AGE (50)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Object name maximum length.
|
|
||||||
#ifndef SPIFFS_OBJ_NAME_LEN
|
|
||||||
#define SPIFFS_OBJ_NAME_LEN (32)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Size of buffer allocated on stack used when copying data.
|
|
||||||
// Lower value generates more read/writes. No meaning having it bigger
|
|
||||||
// than logical page size.
|
|
||||||
#ifndef SPIFFS_COPY_BUFFER_STACK
|
|
||||||
#define SPIFFS_COPY_BUFFER_STACK (64)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Enable this to have an identifiable spiffs filesystem. This will look for
|
|
||||||
// a magic in all sectors to determine if this is a valid spiffs system or
|
|
||||||
// not on mount point. If not, SPIFFS_format must be called prior to mounting
|
|
||||||
// again.
|
|
||||||
#ifndef SPIFFS_USE_MAGIC
|
|
||||||
#define SPIFFS_USE_MAGIC (1)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// SPIFFS_LOCK and SPIFFS_UNLOCK protects spiffs from reentrancy on api level
|
|
||||||
// These should be defined on a multithreaded system
|
|
||||||
|
|
||||||
// define this to enter a mutex if you're running on a multithreaded system
|
|
||||||
#ifndef SPIFFS_LOCK
|
|
||||||
#define SPIFFS_LOCK(fs)
|
|
||||||
#endif
|
|
||||||
// define this to exit a mutex if you're running on a multithreaded system
|
|
||||||
#ifndef SPIFFS_UNLOCK
|
|
||||||
#define SPIFFS_UNLOCK(fs)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
// Enable if only one spiffs instance with constant configuration will exist
|
|
||||||
// on the target. This will reduce calculations, flash and memory accesses.
|
|
||||||
// Parts of configuration must be defined below instead of at time of mount.
|
|
||||||
#ifndef SPIFFS_SINGLETON
|
|
||||||
#define SPIFFS_SINGLETON 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if SPIFFS_SINGLETON
|
|
||||||
// Instead of giving parameters in config struct, singleton build must
|
|
||||||
// give parameters in defines below.
|
|
||||||
#ifndef SPIFFS_CFG_PHYS_SZ
|
|
||||||
#define SPIFFS_CFG_PHYS_SZ(ignore) (1024*1024*2)
|
|
||||||
#endif
|
|
||||||
#ifndef SPIFFS_CFG_PHYS_ERASE_SZ
|
|
||||||
#define SPIFFS_CFG_PHYS_ERASE_SZ(ignore) (65536)
|
|
||||||
#endif
|
|
||||||
#ifndef SPIFFS_CFG_PHYS_ADDR
|
|
||||||
#define SPIFFS_CFG_PHYS_ADDR(ignore) (0)
|
|
||||||
#endif
|
|
||||||
#ifndef SPIFFS_CFG_LOG_PAGE_SZ
|
|
||||||
#define SPIFFS_CFG_LOG_PAGE_SZ(ignore) (256)
|
|
||||||
#endif
|
|
||||||
#ifndef SPIFFS_CFG_LOG_BLOCK_SZ
|
|
||||||
#define SPIFFS_CFG_LOG_BLOCK_SZ(ignore) (65536)
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Enable this if your target needs aligned data for index tables
|
|
||||||
#ifndef SPIFFS_ALIGNED_OBJECT_INDEX_TABLES
|
|
||||||
#define SPIFFS_ALIGNED_OBJECT_INDEX_TABLES 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Enable this if you want the HAL callbacks to be called with the spiffs struct
|
|
||||||
#ifndef SPIFFS_HAL_CALLBACK_EXTRA
|
|
||||||
#define SPIFFS_HAL_CALLBACK_EXTRA 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Enable this if you want to add an integer offset to all file handles
|
|
||||||
// (spiffs_file). This is useful if running multiple instances of spiffs on
|
|
||||||
// same target, in order to recognise to what spiffs instance a file handle
|
|
||||||
// belongs.
|
|
||||||
// NB: This adds config field fh_ix_offset in the configuration struct when
|
|
||||||
// mounting, which must be defined.
|
|
||||||
#ifndef SPIFFS_FILEHDL_OFFSET
|
|
||||||
#define SPIFFS_FILEHDL_OFFSET 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Set SPIFFS_TEST_VISUALISATION to non-zero to enable SPIFFS_vis function
|
|
||||||
// in the api. This function will visualize all filesystem using given printf
|
|
||||||
// function.
|
|
||||||
#ifndef SPIFFS_TEST_VISUALISATION
|
|
||||||
#define SPIFFS_TEST_VISUALISATION 1
|
|
||||||
#endif
|
|
||||||
#if SPIFFS_TEST_VISUALISATION
|
|
||||||
#ifndef spiffs_printf
|
|
||||||
#define spiffs_printf(...) c_printf(__VA_ARGS__)
|
|
||||||
#endif
|
|
||||||
// spiffs_printf argument for a free page
|
|
||||||
#ifndef SPIFFS_TEST_VIS_FREE_STR
|
|
||||||
#define SPIFFS_TEST_VIS_FREE_STR "_"
|
|
||||||
#endif
|
|
||||||
// spiffs_printf argument for a deleted page
|
|
||||||
#ifndef SPIFFS_TEST_VIS_DELE_STR
|
|
||||||
#define SPIFFS_TEST_VIS_DELE_STR "/"
|
|
||||||
#endif
|
|
||||||
// spiffs_printf argument for an index page for given object id
|
|
||||||
#ifndef SPIFFS_TEST_VIS_INDX_STR
|
|
||||||
#define SPIFFS_TEST_VIS_INDX_STR(id) "i"
|
|
||||||
#endif
|
|
||||||
// spiffs_printf argument for a data page for given object id
|
|
||||||
#ifndef SPIFFS_TEST_VIS_DATA_STR
|
|
||||||
#define SPIFFS_TEST_VIS_DATA_STR(id) "d"
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Types depending on configuration such as the amount of flash bytes
|
|
||||||
// given to spiffs file system in total (spiffs_file_system_size),
|
|
||||||
// the logical block size (log_block_size), and the logical page size
|
|
||||||
// (log_page_size)
|
|
||||||
|
|
||||||
// Block index type. Make sure the size of this type can hold
|
|
||||||
// the highest number of all blocks - i.e. spiffs_file_system_size / log_block_size
|
|
||||||
typedef u16_t spiffs_block_ix;
|
|
||||||
// Page index type. Make sure the size of this type can hold
|
|
||||||
// the highest page number of all pages - i.e. spiffs_file_system_size / log_page_size
|
|
||||||
typedef u16_t spiffs_page_ix;
|
|
||||||
// Object id type - most significant bit is reserved for index flag. Make sure the
|
|
||||||
// size of this type can hold the highest object id on a full system,
|
|
||||||
// i.e. 2 + (spiffs_file_system_size / (2*log_page_size))*2
|
|
||||||
typedef u16_t spiffs_obj_id;
|
|
||||||
// Object span index type. Make sure the size of this type can
|
|
||||||
// hold the largest possible span index on the system -
|
|
||||||
// i.e. (spiffs_file_system_size / log_page_size) - 1
|
|
||||||
typedef u16_t spiffs_span_ix;
|
|
||||||
|
|
||||||
#endif /* SPIFFS_CONFIG_H_ */
|
|
||||||
@@ -1,576 +0,0 @@
|
|||||||
#include "spiffs.h"
|
|
||||||
#include "spiffs_nucleus.h"
|
|
||||||
|
|
||||||
#if !SPIFFS_READ_ONLY
|
|
||||||
|
|
||||||
// Erases a logical block and updates the erase counter.
|
|
||||||
// If cache is enabled, all pages that might be cached in this block
|
|
||||||
// is dropped.
|
|
||||||
static s32_t spiffs_gc_erase_block(
|
|
||||||
spiffs *fs,
|
|
||||||
spiffs_block_ix bix) {
|
|
||||||
s32_t res;
|
|
||||||
|
|
||||||
SPIFFS_GC_DBG("gc: erase block %i\n", bix);
|
|
||||||
res = spiffs_erase_block(fs, bix);
|
|
||||||
SPIFFS_CHECK_RES(res);
|
|
||||||
|
|
||||||
#if SPIFFS_CACHE
|
|
||||||
{
|
|
||||||
u32_t i;
|
|
||||||
for (i = 0; i < SPIFFS_PAGES_PER_BLOCK(fs); i++) {
|
|
||||||
spiffs_cache_drop_page(fs, SPIFFS_PAGE_FOR_BLOCK(fs, bix) + i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Searches for blocks where all entries are deleted - if one is found,
|
|
||||||
// the block is erased. Compared to the non-quick gc, the quick one ensures
|
|
||||||
// that no updates are needed on existing objects on pages that are erased.
|
|
||||||
s32_t spiffs_gc_quick(
|
|
||||||
spiffs *fs, u16_t max_free_pages) {
|
|
||||||
s32_t res = SPIFFS_OK;
|
|
||||||
u32_t blocks = fs->block_count;
|
|
||||||
spiffs_block_ix cur_block = 0;
|
|
||||||
u32_t cur_block_addr = 0;
|
|
||||||
int cur_entry = 0;
|
|
||||||
spiffs_obj_id *obj_lu_buf = (spiffs_obj_id *)fs->lu_work;
|
|
||||||
|
|
||||||
SPIFFS_GC_DBG("gc_quick: running\n");
|
|
||||||
#if SPIFFS_GC_STATS
|
|
||||||
fs->stats_gc_runs++;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int entries_per_page = (SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id));
|
|
||||||
|
|
||||||
// find fully deleted blocks
|
|
||||||
// check each block
|
|
||||||
while (res == SPIFFS_OK && blocks--) {
|
|
||||||
u16_t deleted_pages_in_block = 0;
|
|
||||||
u16_t free_pages_in_block = 0;
|
|
||||||
|
|
||||||
int obj_lookup_page = 0;
|
|
||||||
// check each object lookup page
|
|
||||||
while (res == SPIFFS_OK && obj_lookup_page < (int)SPIFFS_OBJ_LOOKUP_PAGES(fs)) {
|
|
||||||
int entry_offset = obj_lookup_page * entries_per_page;
|
|
||||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ,
|
|
||||||
0, cur_block_addr + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);
|
|
||||||
// check each entry
|
|
||||||
while (res == SPIFFS_OK &&
|
|
||||||
cur_entry - entry_offset < entries_per_page &&
|
|
||||||
cur_entry < (int)(SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs))) {
|
|
||||||
spiffs_obj_id obj_id = obj_lu_buf[cur_entry-entry_offset];
|
|
||||||
if (obj_id == SPIFFS_OBJ_ID_DELETED) {
|
|
||||||
deleted_pages_in_block++;
|
|
||||||
} else if (obj_id == SPIFFS_OBJ_ID_FREE) {
|
|
||||||
// kill scan, go for next block
|
|
||||||
free_pages_in_block++;
|
|
||||||
if (free_pages_in_block > max_free_pages) {
|
|
||||||
obj_lookup_page = SPIFFS_OBJ_LOOKUP_PAGES(fs);
|
|
||||||
res = 1; // kill object lu loop
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// kill scan, go for next block
|
|
||||||
obj_lookup_page = SPIFFS_OBJ_LOOKUP_PAGES(fs);
|
|
||||||
res = 1; // kill object lu loop
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
cur_entry++;
|
|
||||||
} // per entry
|
|
||||||
obj_lookup_page++;
|
|
||||||
} // per object lookup page
|
|
||||||
if (res == 1) res = SPIFFS_OK;
|
|
||||||
|
|
||||||
if (res == SPIFFS_OK &&
|
|
||||||
deleted_pages_in_block + free_pages_in_block == SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs) &&
|
|
||||||
free_pages_in_block <= max_free_pages) {
|
|
||||||
// found a fully deleted block
|
|
||||||
fs->stats_p_deleted -= deleted_pages_in_block;
|
|
||||||
res = spiffs_gc_erase_block(fs, cur_block);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
cur_entry = 0;
|
|
||||||
cur_block++;
|
|
||||||
cur_block_addr += SPIFFS_CFG_LOG_BLOCK_SZ(fs);
|
|
||||||
} // per block
|
|
||||||
|
|
||||||
if (res == SPIFFS_OK) {
|
|
||||||
res = SPIFFS_ERR_NO_DELETED_BLOCKS;
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Checks if garbage collecting is necessary. If so a candidate block is found,
|
|
||||||
// cleansed and erased
|
|
||||||
s32_t spiffs_gc_check(
|
|
||||||
spiffs *fs,
|
|
||||||
u32_t len) {
|
|
||||||
s32_t res;
|
|
||||||
s32_t free_pages =
|
|
||||||
(SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs)) * (fs->block_count-2)
|
|
||||||
- fs->stats_p_allocated - fs->stats_p_deleted;
|
|
||||||
int tries = 0;
|
|
||||||
|
|
||||||
if (fs->free_blocks > 3 &&
|
|
||||||
(s32_t)len < free_pages * (s32_t)SPIFFS_DATA_PAGE_SIZE(fs)) {
|
|
||||||
return SPIFFS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
u32_t needed_pages = (len + SPIFFS_DATA_PAGE_SIZE(fs) - 1) / SPIFFS_DATA_PAGE_SIZE(fs);
|
|
||||||
// if (fs->free_blocks <= 2 && (s32_t)needed_pages > free_pages) {
|
|
||||||
// SPIFFS_GC_DBG("gc: full freeblk:%i needed:%i free:%i dele:%i\n", fs->free_blocks, needed_pages, free_pages, fs->stats_p_deleted);
|
|
||||||
// return SPIFFS_ERR_FULL;
|
|
||||||
// }
|
|
||||||
if ((s32_t)needed_pages > (s32_t)(free_pages + fs->stats_p_deleted)) {
|
|
||||||
SPIFFS_GC_DBG("gc_check: full freeblk:%i needed:%i free:%i dele:%i\n", fs->free_blocks, needed_pages, free_pages, fs->stats_p_deleted);
|
|
||||||
return SPIFFS_ERR_FULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
do {
|
|
||||||
SPIFFS_GC_DBG("\ngc_check #%i: run gc free_blocks:%i pfree:%i pallo:%i pdele:%i [%i] len:%i of %i\n",
|
|
||||||
tries,
|
|
||||||
fs->free_blocks, free_pages, fs->stats_p_allocated, fs->stats_p_deleted, (free_pages+fs->stats_p_allocated+fs->stats_p_deleted),
|
|
||||||
len, free_pages*SPIFFS_DATA_PAGE_SIZE(fs));
|
|
||||||
|
|
||||||
spiffs_block_ix *cands;
|
|
||||||
int count;
|
|
||||||
spiffs_block_ix cand;
|
|
||||||
s32_t prev_free_pages = free_pages;
|
|
||||||
// if the fs is crammed, ignore block age when selecting candidate - kind of a bad state
|
|
||||||
res = spiffs_gc_find_candidate(fs, &cands, &count, free_pages <= 0);
|
|
||||||
SPIFFS_CHECK_RES(res);
|
|
||||||
if (count == 0) {
|
|
||||||
SPIFFS_GC_DBG("gc_check: no candidates, return\n");
|
|
||||||
return (s32_t)needed_pages < free_pages ? SPIFFS_OK : SPIFFS_ERR_FULL;
|
|
||||||
}
|
|
||||||
#if SPIFFS_GC_STATS
|
|
||||||
fs->stats_gc_runs++;
|
|
||||||
#endif
|
|
||||||
cand = cands[0];
|
|
||||||
fs->cleaning = 1;
|
|
||||||
//printf("gcing: cleaning block %i\n", cand);
|
|
||||||
res = spiffs_gc_clean(fs, cand);
|
|
||||||
fs->cleaning = 0;
|
|
||||||
if (res < 0) {
|
|
||||||
SPIFFS_GC_DBG("gc_check: cleaning block %i, result %i\n", cand, res);
|
|
||||||
} else {
|
|
||||||
SPIFFS_GC_DBG("gc_check: cleaning block %i, result %i\n", cand, res);
|
|
||||||
}
|
|
||||||
SPIFFS_CHECK_RES(res);
|
|
||||||
|
|
||||||
res = spiffs_gc_erase_page_stats(fs, cand);
|
|
||||||
SPIFFS_CHECK_RES(res);
|
|
||||||
|
|
||||||
res = spiffs_gc_erase_block(fs, cand);
|
|
||||||
SPIFFS_CHECK_RES(res);
|
|
||||||
|
|
||||||
free_pages =
|
|
||||||
(SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs)) * (fs->block_count - 2)
|
|
||||||
- fs->stats_p_allocated - fs->stats_p_deleted;
|
|
||||||
|
|
||||||
if (prev_free_pages <= 0 && prev_free_pages == free_pages) {
|
|
||||||
// abort early to reduce wear, at least tried once
|
|
||||||
SPIFFS_GC_DBG("gc_check: early abort, no result on gc when fs crammed\n");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
} while (++tries < SPIFFS_GC_MAX_RUNS && (fs->free_blocks <= 2 ||
|
|
||||||
(s32_t)len > free_pages*(s32_t)SPIFFS_DATA_PAGE_SIZE(fs)));
|
|
||||||
|
|
||||||
free_pages =
|
|
||||||
(SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs)) * (fs->block_count - 2)
|
|
||||||
- fs->stats_p_allocated - fs->stats_p_deleted;
|
|
||||||
if ((s32_t)len > free_pages*(s32_t)SPIFFS_DATA_PAGE_SIZE(fs)) {
|
|
||||||
res = SPIFFS_ERR_FULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
SPIFFS_GC_DBG("gc_check: finished, %i dirty, blocks %i free, %i pages free, %i tries, res %i\n",
|
|
||||||
fs->stats_p_allocated + fs->stats_p_deleted,
|
|
||||||
fs->free_blocks, free_pages, tries, res);
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Updates page statistics for a block that is about to be erased
|
|
||||||
s32_t spiffs_gc_erase_page_stats(
|
|
||||||
spiffs *fs,
|
|
||||||
spiffs_block_ix bix) {
|
|
||||||
s32_t res = SPIFFS_OK;
|
|
||||||
int obj_lookup_page = 0;
|
|
||||||
int entries_per_page = (SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id));
|
|
||||||
spiffs_obj_id *obj_lu_buf = (spiffs_obj_id *)fs->lu_work;
|
|
||||||
int cur_entry = 0;
|
|
||||||
u32_t dele = 0;
|
|
||||||
u32_t allo = 0;
|
|
||||||
|
|
||||||
// check each object lookup page
|
|
||||||
while (res == SPIFFS_OK && obj_lookup_page < (int)SPIFFS_OBJ_LOOKUP_PAGES(fs)) {
|
|
||||||
int entry_offset = obj_lookup_page * entries_per_page;
|
|
||||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ,
|
|
||||||
0, bix * SPIFFS_CFG_LOG_BLOCK_SZ(fs) + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);
|
|
||||||
// check each entry
|
|
||||||
while (res == SPIFFS_OK &&
|
|
||||||
cur_entry - entry_offset < entries_per_page && cur_entry < (int)(SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs))) {
|
|
||||||
spiffs_obj_id obj_id = obj_lu_buf[cur_entry-entry_offset];
|
|
||||||
if (obj_id == SPIFFS_OBJ_ID_FREE) {
|
|
||||||
} else if (obj_id == SPIFFS_OBJ_ID_DELETED) {
|
|
||||||
dele++;
|
|
||||||
} else {
|
|
||||||
allo++;
|
|
||||||
}
|
|
||||||
cur_entry++;
|
|
||||||
} // per entry
|
|
||||||
obj_lookup_page++;
|
|
||||||
} // per object lookup page
|
|
||||||
SPIFFS_GC_DBG("gc_check: wipe pallo:%i pdele:%i\n", allo, dele);
|
|
||||||
fs->stats_p_allocated -= allo;
|
|
||||||
fs->stats_p_deleted -= dele;
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Finds block candidates to erase
|
|
||||||
s32_t spiffs_gc_find_candidate(
|
|
||||||
spiffs *fs,
|
|
||||||
spiffs_block_ix **block_candidates,
|
|
||||||
int *candidate_count,
|
|
||||||
char fs_crammed) {
|
|
||||||
s32_t res = SPIFFS_OK;
|
|
||||||
u32_t blocks = fs->block_count;
|
|
||||||
spiffs_block_ix cur_block = 0;
|
|
||||||
u32_t cur_block_addr = 0;
|
|
||||||
spiffs_obj_id *obj_lu_buf = (spiffs_obj_id *)fs->lu_work;
|
|
||||||
int cur_entry = 0;
|
|
||||||
|
|
||||||
// using fs->work area as sorted candidate memory, (spiffs_block_ix)cand_bix/(s32_t)score
|
|
||||||
int max_candidates = MIN(fs->block_count, (SPIFFS_CFG_LOG_PAGE_SZ(fs)-8)/(sizeof(spiffs_block_ix) + sizeof(s32_t)));
|
|
||||||
*candidate_count = 0;
|
|
||||||
memset(fs->work, 0xff, SPIFFS_CFG_LOG_PAGE_SZ(fs));
|
|
||||||
|
|
||||||
// divide up work area into block indices and scores
|
|
||||||
spiffs_block_ix *cand_blocks = (spiffs_block_ix *)fs->work;
|
|
||||||
s32_t *cand_scores = (s32_t *)(fs->work + max_candidates * sizeof(spiffs_block_ix));
|
|
||||||
|
|
||||||
// align cand_scores on s32_t boundary
|
|
||||||
#pragma GCC diagnostic push
|
|
||||||
#pragma GCC diagnostic ignored "-Wpointer-to-int-cast"
|
|
||||||
cand_scores = (s32_t*)(((ptrdiff_t)cand_scores + sizeof(ptrdiff_t) - 1) & ~(sizeof(ptrdiff_t) - 1));
|
|
||||||
#pragma GCC diagnostic pop
|
|
||||||
|
|
||||||
*block_candidates = cand_blocks;
|
|
||||||
|
|
||||||
int entries_per_page = (SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id));
|
|
||||||
|
|
||||||
// check each block
|
|
||||||
while (res == SPIFFS_OK && blocks--) {
|
|
||||||
u16_t deleted_pages_in_block = 0;
|
|
||||||
u16_t used_pages_in_block = 0;
|
|
||||||
|
|
||||||
int obj_lookup_page = 0;
|
|
||||||
// check each object lookup page
|
|
||||||
while (res == SPIFFS_OK && obj_lookup_page < (int)SPIFFS_OBJ_LOOKUP_PAGES(fs)) {
|
|
||||||
int entry_offset = obj_lookup_page * entries_per_page;
|
|
||||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ,
|
|
||||||
0, cur_block_addr + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);
|
|
||||||
// check each entry
|
|
||||||
while (res == SPIFFS_OK &&
|
|
||||||
cur_entry - entry_offset < entries_per_page &&
|
|
||||||
cur_entry < (int)(SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs))) {
|
|
||||||
spiffs_obj_id obj_id = obj_lu_buf[cur_entry-entry_offset];
|
|
||||||
if (obj_id == SPIFFS_OBJ_ID_FREE) {
|
|
||||||
// when a free entry is encountered, scan logic ensures that all following entries are free also
|
|
||||||
res = 1; // kill object lu loop
|
|
||||||
break;
|
|
||||||
} else if (obj_id == SPIFFS_OBJ_ID_DELETED) {
|
|
||||||
deleted_pages_in_block++;
|
|
||||||
} else {
|
|
||||||
used_pages_in_block++;
|
|
||||||
}
|
|
||||||
cur_entry++;
|
|
||||||
} // per entry
|
|
||||||
obj_lookup_page++;
|
|
||||||
} // per object lookup page
|
|
||||||
if (res == 1) res = SPIFFS_OK;
|
|
||||||
|
|
||||||
// calculate score and insert into candidate table
|
|
||||||
// stoneage sort, but probably not so many blocks
|
|
||||||
if (res == SPIFFS_OK && deleted_pages_in_block > 0) {
|
|
||||||
// read erase count
|
|
||||||
spiffs_obj_id erase_count;
|
|
||||||
res = _spiffs_rd(fs, SPIFFS_OP_C_READ | SPIFFS_OP_T_OBJ_LU2, 0,
|
|
||||||
SPIFFS_ERASE_COUNT_PADDR(fs, cur_block),
|
|
||||||
sizeof(spiffs_obj_id), (u8_t *)&erase_count);
|
|
||||||
SPIFFS_CHECK_RES(res);
|
|
||||||
|
|
||||||
spiffs_obj_id erase_age;
|
|
||||||
if (fs->max_erase_count > erase_count) {
|
|
||||||
erase_age = fs->max_erase_count - erase_count;
|
|
||||||
} else {
|
|
||||||
erase_age = SPIFFS_OBJ_ID_FREE - (erase_count - fs->max_erase_count);
|
|
||||||
}
|
|
||||||
|
|
||||||
s32_t score =
|
|
||||||
deleted_pages_in_block * SPIFFS_GC_HEUR_W_DELET +
|
|
||||||
used_pages_in_block * SPIFFS_GC_HEUR_W_USED +
|
|
||||||
erase_age * (fs_crammed ? 0 : SPIFFS_GC_HEUR_W_ERASE_AGE);
|
|
||||||
int cand_ix = 0;
|
|
||||||
SPIFFS_GC_DBG("gc_check: bix:%i del:%i use:%i score:%i\n", cur_block, deleted_pages_in_block, used_pages_in_block, score);
|
|
||||||
while (cand_ix < max_candidates) {
|
|
||||||
if (cand_blocks[cand_ix] == (spiffs_block_ix)-1) {
|
|
||||||
cand_blocks[cand_ix] = cur_block;
|
|
||||||
cand_scores[cand_ix] = score;
|
|
||||||
break;
|
|
||||||
} else if (cand_scores[cand_ix] < score) {
|
|
||||||
int reorder_cand_ix = max_candidates - 2;
|
|
||||||
while (reorder_cand_ix >= cand_ix) {
|
|
||||||
cand_blocks[reorder_cand_ix + 1] = cand_blocks[reorder_cand_ix];
|
|
||||||
cand_scores[reorder_cand_ix + 1] = cand_scores[reorder_cand_ix];
|
|
||||||
reorder_cand_ix--;
|
|
||||||
}
|
|
||||||
cand_blocks[cand_ix] = cur_block;
|
|
||||||
cand_scores[cand_ix] = score;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
cand_ix++;
|
|
||||||
}
|
|
||||||
(*candidate_count)++;
|
|
||||||
}
|
|
||||||
|
|
||||||
cur_entry = 0;
|
|
||||||
cur_block++;
|
|
||||||
cur_block_addr += SPIFFS_CFG_LOG_BLOCK_SZ(fs);
|
|
||||||
} // per block
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
FIND_OBJ_DATA,
|
|
||||||
MOVE_OBJ_DATA,
|
|
||||||
MOVE_OBJ_IX,
|
|
||||||
FINISHED
|
|
||||||
} spiffs_gc_clean_state;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
spiffs_gc_clean_state state;
|
|
||||||
spiffs_obj_id cur_obj_id;
|
|
||||||
spiffs_span_ix cur_objix_spix;
|
|
||||||
spiffs_page_ix cur_objix_pix;
|
|
||||||
int stored_scan_entry_index;
|
|
||||||
u8_t obj_id_found;
|
|
||||||
} spiffs_gc;
|
|
||||||
|
|
||||||
// Empties given block by moving all data into free pages of another block
|
|
||||||
// Strategy:
|
|
||||||
// loop:
|
|
||||||
// scan object lookup for object data pages
|
|
||||||
// for first found id, check spix and load corresponding object index page to memory
|
|
||||||
// push object scan lookup entry index
|
|
||||||
// rescan object lookup, find data pages with same id and referenced by same object index
|
|
||||||
// move data page, update object index in memory
|
|
||||||
// when reached end of lookup, store updated object index
|
|
||||||
// pop object scan lookup entry index
|
|
||||||
// repeat loop until end of object lookup
|
|
||||||
// scan object lookup again for remaining object index pages, move to new page in other block
|
|
||||||
//
|
|
||||||
s32_t spiffs_gc_clean(spiffs *fs, spiffs_block_ix bix) {
|
|
||||||
s32_t res = SPIFFS_OK;
|
|
||||||
int entries_per_page = (SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id));
|
|
||||||
int cur_entry = 0;
|
|
||||||
spiffs_obj_id *obj_lu_buf = (spiffs_obj_id *)fs->lu_work;
|
|
||||||
spiffs_gc gc;
|
|
||||||
spiffs_page_ix cur_pix = 0;
|
|
||||||
spiffs_page_object_ix_header *objix_hdr = (spiffs_page_object_ix_header *)fs->work;
|
|
||||||
spiffs_page_object_ix *objix = (spiffs_page_object_ix *)fs->work;
|
|
||||||
|
|
||||||
SPIFFS_GC_DBG("gc_clean: cleaning block %i\n", bix);
|
|
||||||
|
|
||||||
memset(&gc, 0, sizeof(spiffs_gc));
|
|
||||||
gc.state = FIND_OBJ_DATA;
|
|
||||||
|
|
||||||
if (fs->free_cursor_block_ix == bix) {
|
|
||||||
// move free cursor to next block, cannot use free pages from the block we want to clean
|
|
||||||
fs->free_cursor_block_ix = (bix+1)%fs->block_count;
|
|
||||||
fs->free_cursor_obj_lu_entry = 0;
|
|
||||||
SPIFFS_GC_DBG("gc_clean: move free cursor to block %i\n", fs->free_cursor_block_ix);
|
|
||||||
}
|
|
||||||
|
|
||||||
while (res == SPIFFS_OK && gc.state != FINISHED) {
|
|
||||||
SPIFFS_GC_DBG("gc_clean: state = %i entry:%i\n", gc.state, cur_entry);
|
|
||||||
gc.obj_id_found = 0;
|
|
||||||
|
|
||||||
// scan through lookup pages
|
|
||||||
int obj_lookup_page = cur_entry / entries_per_page;
|
|
||||||
u8_t scan = 1;
|
|
||||||
// check each object lookup page
|
|
||||||
while (scan && res == SPIFFS_OK && obj_lookup_page < (int)SPIFFS_OBJ_LOOKUP_PAGES(fs)) {
|
|
||||||
int entry_offset = obj_lookup_page * entries_per_page;
|
|
||||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ,
|
|
||||||
0, bix * SPIFFS_CFG_LOG_BLOCK_SZ(fs) + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page),
|
|
||||||
SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);
|
|
||||||
// check each entry
|
|
||||||
while (scan && res == SPIFFS_OK &&
|
|
||||||
cur_entry - entry_offset < entries_per_page && cur_entry < (int)(SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs))) {
|
|
||||||
spiffs_obj_id obj_id = obj_lu_buf[cur_entry-entry_offset];
|
|
||||||
cur_pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, cur_entry);
|
|
||||||
|
|
||||||
// act upon object id depending on gc state
|
|
||||||
switch (gc.state) {
|
|
||||||
case FIND_OBJ_DATA:
|
|
||||||
if (obj_id != SPIFFS_OBJ_ID_DELETED && obj_id != SPIFFS_OBJ_ID_FREE &&
|
|
||||||
((obj_id & SPIFFS_OBJ_ID_IX_FLAG) == 0)) {
|
|
||||||
SPIFFS_GC_DBG("gc_clean: FIND_DATA state:%i - found obj id %04x\n", gc.state, obj_id);
|
|
||||||
gc.obj_id_found = 1;
|
|
||||||
gc.cur_obj_id = obj_id;
|
|
||||||
scan = 0;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case MOVE_OBJ_DATA:
|
|
||||||
if (obj_id == gc.cur_obj_id) {
|
|
||||||
spiffs_page_header p_hdr;
|
|
||||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
|
|
||||||
0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t*)&p_hdr);
|
|
||||||
SPIFFS_CHECK_RES(res);
|
|
||||||
SPIFFS_GC_DBG("gc_clean: MOVE_DATA found data page %04x:%04x @ %04x\n", gc.cur_obj_id, p_hdr.span_ix, cur_pix);
|
|
||||||
if (SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, p_hdr.span_ix) != gc.cur_objix_spix) {
|
|
||||||
SPIFFS_GC_DBG("gc_clean: MOVE_DATA no objix spix match, take in another run\n");
|
|
||||||
} else {
|
|
||||||
spiffs_page_ix new_data_pix;
|
|
||||||
if (p_hdr.flags & SPIFFS_PH_FLAG_DELET) {
|
|
||||||
// move page
|
|
||||||
res = spiffs_page_move(fs, 0, 0, obj_id, &p_hdr, cur_pix, &new_data_pix);
|
|
||||||
SPIFFS_GC_DBG("gc_clean: MOVE_DATA move objix %04x:%04x page %04x to %04x\n", gc.cur_obj_id, p_hdr.span_ix, cur_pix, new_data_pix);
|
|
||||||
SPIFFS_CHECK_RES(res);
|
|
||||||
// move wipes obj_lu, reload it
|
|
||||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ,
|
|
||||||
0, bix * SPIFFS_CFG_LOG_BLOCK_SZ(fs) + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page),
|
|
||||||
SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);
|
|
||||||
SPIFFS_CHECK_RES(res);
|
|
||||||
} else {
|
|
||||||
// page is deleted but not deleted in lookup, scrap it
|
|
||||||
SPIFFS_GC_DBG("gc_clean: MOVE_DATA wipe objix %04x:%04x page %04x\n", obj_id, p_hdr.span_ix, cur_pix);
|
|
||||||
res = spiffs_page_delete(fs, cur_pix);
|
|
||||||
SPIFFS_CHECK_RES(res);
|
|
||||||
new_data_pix = SPIFFS_OBJ_ID_FREE;
|
|
||||||
}
|
|
||||||
// update memory representation of object index page with new data page
|
|
||||||
if (gc.cur_objix_spix == 0) {
|
|
||||||
// update object index header page
|
|
||||||
((spiffs_page_ix*)((u8_t *)objix_hdr + sizeof(spiffs_page_object_ix_header)))[p_hdr.span_ix] = new_data_pix;
|
|
||||||
SPIFFS_GC_DBG("gc_clean: MOVE_DATA wrote page %04x to objix_hdr entry %02x in mem\n", new_data_pix, SPIFFS_OBJ_IX_ENTRY(fs, p_hdr.span_ix));
|
|
||||||
} else {
|
|
||||||
// update object index page
|
|
||||||
((spiffs_page_ix*)((u8_t *)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, p_hdr.span_ix)] = new_data_pix;
|
|
||||||
SPIFFS_GC_DBG("gc_clean: MOVE_DATA wrote page %04x to objix entry %02x in mem\n", new_data_pix, SPIFFS_OBJ_IX_ENTRY(fs, p_hdr.span_ix));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case MOVE_OBJ_IX:
|
|
||||||
if (obj_id != SPIFFS_OBJ_ID_DELETED && obj_id != SPIFFS_OBJ_ID_FREE &&
|
|
||||||
(obj_id & SPIFFS_OBJ_ID_IX_FLAG)) {
|
|
||||||
// found an index object id
|
|
||||||
spiffs_page_header p_hdr;
|
|
||||||
spiffs_page_ix new_pix;
|
|
||||||
// load header
|
|
||||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
|
|
||||||
0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t*)&p_hdr);
|
|
||||||
SPIFFS_CHECK_RES(res);
|
|
||||||
if (p_hdr.flags & SPIFFS_PH_FLAG_DELET) {
|
|
||||||
// move page
|
|
||||||
res = spiffs_page_move(fs, 0, 0, obj_id, &p_hdr, cur_pix, &new_pix);
|
|
||||||
SPIFFS_GC_DBG("gc_clean: MOVE_OBJIX move objix %04x:%04x page %04x to %04x\n", obj_id, p_hdr.span_ix, cur_pix, new_pix);
|
|
||||||
SPIFFS_CHECK_RES(res);
|
|
||||||
spiffs_cb_object_event(fs, 0, SPIFFS_EV_IX_UPD, obj_id, p_hdr.span_ix, new_pix, 0);
|
|
||||||
// move wipes obj_lu, reload it
|
|
||||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ,
|
|
||||||
0, bix * SPIFFS_CFG_LOG_BLOCK_SZ(fs) + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page),
|
|
||||||
SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);
|
|
||||||
SPIFFS_CHECK_RES(res);
|
|
||||||
} else {
|
|
||||||
// page is deleted but not deleted in lookup, scrap it
|
|
||||||
SPIFFS_GC_DBG("gc_clean: MOVE_OBJIX wipe objix %04x:%04x page %04x\n", obj_id, p_hdr.span_ix, cur_pix);
|
|
||||||
res = spiffs_page_delete(fs, cur_pix);
|
|
||||||
if (res == SPIFFS_OK) {
|
|
||||||
spiffs_cb_object_event(fs, 0, SPIFFS_EV_IX_DEL, obj_id, p_hdr.span_ix, cur_pix, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SPIFFS_CHECK_RES(res);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
scan = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
cur_entry++;
|
|
||||||
} // per entry
|
|
||||||
obj_lookup_page++;
|
|
||||||
} // per object lookup page
|
|
||||||
|
|
||||||
if (res != SPIFFS_OK) break;
|
|
||||||
|
|
||||||
// state finalization and switch
|
|
||||||
switch (gc.state) {
|
|
||||||
case FIND_OBJ_DATA:
|
|
||||||
if (gc.obj_id_found) {
|
|
||||||
// find out corresponding obj ix page and load it to memory
|
|
||||||
spiffs_page_header p_hdr;
|
|
||||||
spiffs_page_ix objix_pix;
|
|
||||||
gc.stored_scan_entry_index = cur_entry;
|
|
||||||
cur_entry = 0;
|
|
||||||
gc.state = MOVE_OBJ_DATA;
|
|
||||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
|
|
||||||
0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t*)&p_hdr);
|
|
||||||
SPIFFS_CHECK_RES(res);
|
|
||||||
gc.cur_objix_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, p_hdr.span_ix);
|
|
||||||
SPIFFS_GC_DBG("gc_clean: FIND_DATA find objix span_ix:%04x\n", gc.cur_objix_spix);
|
|
||||||
res = spiffs_obj_lu_find_id_and_span(fs, gc.cur_obj_id | SPIFFS_OBJ_ID_IX_FLAG, gc.cur_objix_spix, 0, &objix_pix);
|
|
||||||
SPIFFS_CHECK_RES(res);
|
|
||||||
SPIFFS_GC_DBG("gc_clean: FIND_DATA found object index at page %04x\n", objix_pix);
|
|
||||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
|
|
||||||
0, SPIFFS_PAGE_TO_PADDR(fs, objix_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work);
|
|
||||||
SPIFFS_CHECK_RES(res);
|
|
||||||
SPIFFS_VALIDATE_OBJIX(objix->p_hdr, gc.cur_obj_id | SPIFFS_OBJ_ID_IX_FLAG, gc.cur_objix_spix);
|
|
||||||
gc.cur_objix_pix = objix_pix;
|
|
||||||
} else {
|
|
||||||
gc.state = MOVE_OBJ_IX;
|
|
||||||
cur_entry = 0; // restart entry scan index
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case MOVE_OBJ_DATA: {
|
|
||||||
// store modified objix (hdr) page
|
|
||||||
spiffs_page_ix new_objix_pix;
|
|
||||||
gc.state = FIND_OBJ_DATA;
|
|
||||||
cur_entry = gc.stored_scan_entry_index;
|
|
||||||
if (gc.cur_objix_spix == 0) {
|
|
||||||
// store object index header page
|
|
||||||
res = spiffs_object_update_index_hdr(fs, 0, gc.cur_obj_id | SPIFFS_OBJ_ID_IX_FLAG, gc.cur_objix_pix, fs->work, 0, 0, &new_objix_pix);
|
|
||||||
SPIFFS_GC_DBG("gc_clean: MOVE_DATA store modified objix_hdr page, %04x:%04x\n", new_objix_pix, 0);
|
|
||||||
SPIFFS_CHECK_RES(res);
|
|
||||||
} else {
|
|
||||||
// store object index page
|
|
||||||
res = spiffs_page_move(fs, 0, fs->work, gc.cur_obj_id | SPIFFS_OBJ_ID_IX_FLAG, 0, gc.cur_objix_pix, &new_objix_pix);
|
|
||||||
SPIFFS_GC_DBG("gc_clean: MOVE_DATA store modified objix page, %04x:%04x\n", new_objix_pix, objix->p_hdr.span_ix);
|
|
||||||
SPIFFS_CHECK_RES(res);
|
|
||||||
spiffs_cb_object_event(fs, 0, SPIFFS_EV_IX_UPD, gc.cur_obj_id, objix->p_hdr.span_ix, new_objix_pix, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case MOVE_OBJ_IX:
|
|
||||||
gc.state = FINISHED;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
cur_entry = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
SPIFFS_GC_DBG("gc_clean: state-> %i\n", gc.state);
|
|
||||||
} // while state != FINISHED
|
|
||||||
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // !SPIFFS_READ_ONLY
|
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,751 +0,0 @@
|
|||||||
/*
|
|
||||||
* spiffs_nucleus.h
|
|
||||||
*
|
|
||||||
* Created on: Jun 15, 2013
|
|
||||||
* Author: petera
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* SPIFFS layout
|
|
||||||
*
|
|
||||||
* spiffs is designed for following spi flash characteristics:
|
|
||||||
* - only big areas of data (blocks) can be erased
|
|
||||||
* - erasing resets all bits in a block to ones
|
|
||||||
* - writing pulls ones to zeroes
|
|
||||||
* - zeroes cannot be pulled to ones, without erase
|
|
||||||
* - wear leveling
|
|
||||||
*
|
|
||||||
* spiffs is also meant to be run on embedded, memory constraint devices.
|
|
||||||
*
|
|
||||||
* Entire area is divided in blocks. Entire area is also divided in pages.
|
|
||||||
* Each block contains same number of pages. A page cannot be erased, but a
|
|
||||||
* block can be erased.
|
|
||||||
*
|
|
||||||
* Entire area must be block_size * x
|
|
||||||
* page_size must be block_size / (2^y) where y > 2
|
|
||||||
*
|
|
||||||
* ex: area = 1024*1024 bytes, block size = 65536 bytes, page size = 256 bytes
|
|
||||||
*
|
|
||||||
* BLOCK 0 PAGE 0 object lookup 1
|
|
||||||
* PAGE 1 object lookup 2
|
|
||||||
* ...
|
|
||||||
* PAGE n-1 object lookup n
|
|
||||||
* PAGE n object data 1
|
|
||||||
* PAGE n+1 object data 2
|
|
||||||
* ...
|
|
||||||
* PAGE n+m-1 object data m
|
|
||||||
*
|
|
||||||
* BLOCK 1 PAGE n+m object lookup 1
|
|
||||||
* PAGE n+m+1 object lookup 2
|
|
||||||
* ...
|
|
||||||
* PAGE 2n+m-1 object lookup n
|
|
||||||
* PAGE 2n+m object data 1
|
|
||||||
* PAGE 2n+m object data 2
|
|
||||||
* ...
|
|
||||||
* PAGE 2n+2m-1 object data m
|
|
||||||
* ...
|
|
||||||
*
|
|
||||||
* n is number of object lookup pages, which is number of pages needed to index all pages
|
|
||||||
* in a block by object id
|
|
||||||
* : block_size / page_size * sizeof(obj_id) / page_size
|
|
||||||
* m is number data pages, which is number of pages in block minus number of lookup pages
|
|
||||||
* : block_size / page_size - block_size / page_size * sizeof(obj_id) / page_size
|
|
||||||
* thus, n+m is total number of pages in a block
|
|
||||||
* : block_size / page_size
|
|
||||||
*
|
|
||||||
* ex: n = 65536/256*2/256 = 2, m = 65536/256 - 2 = 254 => n+m = 65536/256 = 256
|
|
||||||
*
|
|
||||||
* Object lookup pages contain object id entries. Each entry represent the corresponding
|
|
||||||
* data page.
|
|
||||||
* Assuming a 16 bit object id, an object id being 0xffff represents a free page.
|
|
||||||
* An object id being 0x0000 represents a deleted page.
|
|
||||||
*
|
|
||||||
* ex: page 0 : lookup : 0008 0001 0aaa ffff ffff ffff ffff ffff ..
|
|
||||||
* page 1 : lookup : ffff ffff ffff ffff ffff ffff ffff ffff ..
|
|
||||||
* page 2 : data : data for object id 0008
|
|
||||||
* page 3 : data : data for object id 0001
|
|
||||||
* page 4 : data : data for object id 0aaa
|
|
||||||
* ...
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* Object data pages can be either object index pages or object content.
|
|
||||||
* All object data pages contains a data page header, containing object id and span index.
|
|
||||||
* The span index denotes the object page ordering amongst data pages with same object id.
|
|
||||||
* This applies to both object index pages (when index spans more than one page of entries),
|
|
||||||
* and object data pages.
|
|
||||||
* An object index page contains page entries pointing to object content page. The entry index
|
|
||||||
* in a object index page correlates to the span index in the actual object data page.
|
|
||||||
* The first object index page (span index 0) is called object index header page, and also
|
|
||||||
* contains object flags (directory/file), size, object name etc.
|
|
||||||
*
|
|
||||||
* ex:
|
|
||||||
* BLOCK 1
|
|
||||||
* PAGE 256: objectl lookup page 1
|
|
||||||
* [*123] [ 123] [ 123] [ 123]
|
|
||||||
* [ 123] [*123] [ 123] [ 123]
|
|
||||||
* [free] [free] [free] [free] ...
|
|
||||||
* PAGE 257: objectl lookup page 2
|
|
||||||
* [free] [free] [free] [free] ...
|
|
||||||
* PAGE 258: object index page (header)
|
|
||||||
* obj.id:0123 span.ix:0000 flags:INDEX
|
|
||||||
* size:1600 name:ex.txt type:file
|
|
||||||
* [259] [260] [261] [262]
|
|
||||||
* PAGE 259: object data page
|
|
||||||
* obj.id:0123 span.ix:0000 flags:DATA
|
|
||||||
* PAGE 260: object data page
|
|
||||||
* obj.id:0123 span.ix:0001 flags:DATA
|
|
||||||
* PAGE 261: object data page
|
|
||||||
* obj.id:0123 span.ix:0002 flags:DATA
|
|
||||||
* PAGE 262: object data page
|
|
||||||
* obj.id:0123 span.ix:0003 flags:DATA
|
|
||||||
* PAGE 263: object index page
|
|
||||||
* obj.id:0123 span.ix:0001 flags:INDEX
|
|
||||||
* [264] [265] [fre] [fre]
|
|
||||||
* [fre] [fre] [fre] [fre]
|
|
||||||
* PAGE 264: object data page
|
|
||||||
* obj.id:0123 span.ix:0004 flags:DATA
|
|
||||||
* PAGE 265: object data page
|
|
||||||
* obj.id:0123 span.ix:0005 flags:DATA
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
#ifndef SPIFFS_NUCLEUS_H_
|
|
||||||
#define SPIFFS_NUCLEUS_H_
|
|
||||||
|
|
||||||
#define _SPIFFS_ERR_CHECK_FIRST (SPIFFS_ERR_INTERNAL - 1)
|
|
||||||
#define SPIFFS_ERR_CHECK_OBJ_ID_MISM (SPIFFS_ERR_INTERNAL - 1)
|
|
||||||
#define SPIFFS_ERR_CHECK_SPIX_MISM (SPIFFS_ERR_INTERNAL - 2)
|
|
||||||
#define SPIFFS_ERR_CHECK_FLAGS_BAD (SPIFFS_ERR_INTERNAL - 3)
|
|
||||||
#define _SPIFFS_ERR_CHECK_LAST (SPIFFS_ERR_INTERNAL - 4)
|
|
||||||
|
|
||||||
#define SPIFFS_VIS_COUNTINUE (SPIFFS_ERR_INTERNAL - 20)
|
|
||||||
#define SPIFFS_VIS_COUNTINUE_RELOAD (SPIFFS_ERR_INTERNAL - 21)
|
|
||||||
#define SPIFFS_VIS_END (SPIFFS_ERR_INTERNAL - 22)
|
|
||||||
|
|
||||||
#define SPIFFS_EV_IX_UPD 0
|
|
||||||
#define SPIFFS_EV_IX_NEW 1
|
|
||||||
#define SPIFFS_EV_IX_DEL 2
|
|
||||||
|
|
||||||
#define SPIFFS_OBJ_ID_IX_FLAG ((spiffs_obj_id)(1<<(8*sizeof(spiffs_obj_id)-1)))
|
|
||||||
|
|
||||||
#define SPIFFS_UNDEFINED_LEN (u32_t)(-1)
|
|
||||||
|
|
||||||
#define SPIFFS_OBJ_ID_DELETED ((spiffs_obj_id)0)
|
|
||||||
#define SPIFFS_OBJ_ID_FREE ((spiffs_obj_id)-1)
|
|
||||||
|
|
||||||
#if SPIFFS_USE_MAGIC
|
|
||||||
#if !SPIFFS_USE_MAGIC_LENGTH
|
|
||||||
#define SPIFFS_MAGIC(fs, bix) \
|
|
||||||
((spiffs_obj_id)(0x20140529 ^ SPIFFS_CFG_LOG_PAGE_SZ(fs)))
|
|
||||||
#else // SPIFFS_USE_MAGIC_LENGTH
|
|
||||||
#define SPIFFS_MAGIC(fs, bix) \
|
|
||||||
((spiffs_obj_id)(0x20140529 ^ SPIFFS_CFG_LOG_PAGE_SZ(fs) ^ ((fs)->block_count - (bix))))
|
|
||||||
#endif // SPIFFS_USE_MAGIC_LENGTH
|
|
||||||
#endif // SPIFFS_USE_MAGIC
|
|
||||||
|
|
||||||
#define SPIFFS_CONFIG_MAGIC (0x20090315)
|
|
||||||
|
|
||||||
#if SPIFFS_SINGLETON == 0
|
|
||||||
#define SPIFFS_CFG_LOG_PAGE_SZ(fs) \
|
|
||||||
((fs)->cfg.log_page_size)
|
|
||||||
#define SPIFFS_CFG_LOG_BLOCK_SZ(fs) \
|
|
||||||
((fs)->cfg.log_block_size)
|
|
||||||
#define SPIFFS_CFG_PHYS_SZ(fs) \
|
|
||||||
((fs)->cfg.phys_size)
|
|
||||||
#define SPIFFS_CFG_PHYS_ERASE_SZ(fs) \
|
|
||||||
((fs)->cfg.phys_erase_block)
|
|
||||||
#define SPIFFS_CFG_PHYS_ADDR(fs) \
|
|
||||||
((fs)->cfg.phys_addr)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// total number of pages
|
|
||||||
#define SPIFFS_MAX_PAGES(fs) \
|
|
||||||
( SPIFFS_CFG_PHYS_SZ(fs)/SPIFFS_CFG_LOG_PAGE_SZ(fs) )
|
|
||||||
// total number of pages per block, including object lookup pages
|
|
||||||
#define SPIFFS_PAGES_PER_BLOCK(fs) \
|
|
||||||
( SPIFFS_CFG_LOG_BLOCK_SZ(fs)/SPIFFS_CFG_LOG_PAGE_SZ(fs) )
|
|
||||||
// number of object lookup pages per block
|
|
||||||
#define SPIFFS_OBJ_LOOKUP_PAGES(fs) \
|
|
||||||
(MAX(1, (SPIFFS_PAGES_PER_BLOCK(fs) * sizeof(spiffs_obj_id)) / SPIFFS_CFG_LOG_PAGE_SZ(fs)) )
|
|
||||||
// checks if page index belongs to object lookup
|
|
||||||
#define SPIFFS_IS_LOOKUP_PAGE(fs,pix) \
|
|
||||||
(((pix) % SPIFFS_PAGES_PER_BLOCK(fs)) < SPIFFS_OBJ_LOOKUP_PAGES(fs))
|
|
||||||
// number of object lookup entries in all object lookup pages
|
|
||||||
#define SPIFFS_OBJ_LOOKUP_MAX_ENTRIES(fs) \
|
|
||||||
(SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs))
|
|
||||||
// converts a block to physical address
|
|
||||||
#define SPIFFS_BLOCK_TO_PADDR(fs, block) \
|
|
||||||
( SPIFFS_CFG_PHYS_ADDR(fs) + (block)* SPIFFS_CFG_LOG_BLOCK_SZ(fs) )
|
|
||||||
// converts a object lookup entry to page index
|
|
||||||
#define SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, block, entry) \
|
|
||||||
((block)*SPIFFS_PAGES_PER_BLOCK(fs) + (SPIFFS_OBJ_LOOKUP_PAGES(fs) + entry))
|
|
||||||
// converts a object lookup entry to physical address of corresponding page
|
|
||||||
#define SPIFFS_OBJ_LOOKUP_ENTRY_TO_PADDR(fs, block, entry) \
|
|
||||||
(SPIFFS_BLOCK_TO_PADDR(fs, block) + (SPIFFS_OBJ_LOOKUP_PAGES(fs) + entry) * SPIFFS_CFG_LOG_PAGE_SZ(fs) )
|
|
||||||
// converts a page to physical address
|
|
||||||
#define SPIFFS_PAGE_TO_PADDR(fs, page) \
|
|
||||||
( SPIFFS_CFG_PHYS_ADDR(fs) + (page) * SPIFFS_CFG_LOG_PAGE_SZ(fs) )
|
|
||||||
// converts a physical address to page
|
|
||||||
#define SPIFFS_PADDR_TO_PAGE(fs, addr) \
|
|
||||||
( ((addr) - SPIFFS_CFG_PHYS_ADDR(fs)) / SPIFFS_CFG_LOG_PAGE_SZ(fs) )
|
|
||||||
// gives index in page for a physical address
|
|
||||||
#define SPIFFS_PADDR_TO_PAGE_OFFSET(fs, addr) \
|
|
||||||
( ((addr) - SPIFFS_CFG_PHYS_ADDR(fs)) % SPIFFS_CFG_LOG_PAGE_SZ(fs) )
|
|
||||||
// returns containing block for given page
|
|
||||||
#define SPIFFS_BLOCK_FOR_PAGE(fs, page) \
|
|
||||||
( (page) / SPIFFS_PAGES_PER_BLOCK(fs) )
|
|
||||||
// returns starting page for block
|
|
||||||
#define SPIFFS_PAGE_FOR_BLOCK(fs, block) \
|
|
||||||
( (block) * SPIFFS_PAGES_PER_BLOCK(fs) )
|
|
||||||
// converts page to entry in object lookup page
|
|
||||||
#define SPIFFS_OBJ_LOOKUP_ENTRY_FOR_PAGE(fs, page) \
|
|
||||||
( (page) % SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs) )
|
|
||||||
// returns data size in a data page
|
|
||||||
#define SPIFFS_DATA_PAGE_SIZE(fs) \
|
|
||||||
( SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_page_header) )
|
|
||||||
// returns physical address for block's erase count,
|
|
||||||
// always in the physical last entry of the last object lookup page
|
|
||||||
#define SPIFFS_ERASE_COUNT_PADDR(fs, bix) \
|
|
||||||
( SPIFFS_BLOCK_TO_PADDR(fs, bix) + SPIFFS_OBJ_LOOKUP_PAGES(fs) * SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_obj_id) )
|
|
||||||
// returns physical address for block's magic,
|
|
||||||
// always in the physical second last entry of the last object lookup page
|
|
||||||
#define SPIFFS_MAGIC_PADDR(fs, bix) \
|
|
||||||
( SPIFFS_BLOCK_TO_PADDR(fs, bix) + SPIFFS_OBJ_LOOKUP_PAGES(fs) * SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_obj_id)*2 )
|
|
||||||
// checks if there is any room for magic in the object luts
|
|
||||||
#define SPIFFS_CHECK_MAGIC_POSSIBLE(fs) \
|
|
||||||
( (SPIFFS_OBJ_LOOKUP_MAX_ENTRIES(fs) % (SPIFFS_CFG_LOG_PAGE_SZ(fs)/sizeof(spiffs_obj_id))) * sizeof(spiffs_obj_id) \
|
|
||||||
<= (SPIFFS_CFG_LOG_PAGE_SZ(fs)-sizeof(spiffs_obj_id)*2) )
|
|
||||||
|
|
||||||
// define helpers object
|
|
||||||
|
|
||||||
// entries in an object header page index
|
|
||||||
#define SPIFFS_OBJ_HDR_IX_LEN(fs) \
|
|
||||||
((SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_page_object_ix_header))/sizeof(spiffs_page_ix))
|
|
||||||
// entries in an object page index
|
|
||||||
#define SPIFFS_OBJ_IX_LEN(fs) \
|
|
||||||
((SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_page_object_ix))/sizeof(spiffs_page_ix))
|
|
||||||
// object index entry for given data span index
|
|
||||||
#define SPIFFS_OBJ_IX_ENTRY(fs, spix) \
|
|
||||||
((spix) < SPIFFS_OBJ_HDR_IX_LEN(fs) ? (spix) : (((spix)-SPIFFS_OBJ_HDR_IX_LEN(fs))%SPIFFS_OBJ_IX_LEN(fs)))
|
|
||||||
// object index span index number for given data span index or entry
|
|
||||||
#define SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, spix) \
|
|
||||||
((spix) < SPIFFS_OBJ_HDR_IX_LEN(fs) ? 0 : (1+((spix)-SPIFFS_OBJ_HDR_IX_LEN(fs))/SPIFFS_OBJ_IX_LEN(fs)))
|
|
||||||
|
|
||||||
|
|
||||||
#define SPIFFS_OP_T_OBJ_LU (0<<0)
|
|
||||||
#define SPIFFS_OP_T_OBJ_LU2 (1<<0)
|
|
||||||
#define SPIFFS_OP_T_OBJ_IX (2<<0)
|
|
||||||
#define SPIFFS_OP_T_OBJ_DA (3<<0)
|
|
||||||
#define SPIFFS_OP_C_DELE (0<<2)
|
|
||||||
#define SPIFFS_OP_C_UPDT (1<<2)
|
|
||||||
#define SPIFFS_OP_C_MOVS (2<<2)
|
|
||||||
#define SPIFFS_OP_C_MOVD (3<<2)
|
|
||||||
#define SPIFFS_OP_C_FLSH (4<<2)
|
|
||||||
#define SPIFFS_OP_C_READ (5<<2)
|
|
||||||
#define SPIFFS_OP_C_WRTHRU (6<<2)
|
|
||||||
|
|
||||||
#define SPIFFS_OP_TYPE_MASK (3<<0)
|
|
||||||
#define SPIFFS_OP_COM_MASK (7<<2)
|
|
||||||
|
|
||||||
|
|
||||||
// if 0, this page is written to, else clean
|
|
||||||
#define SPIFFS_PH_FLAG_USED (1<<0)
|
|
||||||
// if 0, writing is finalized, else under modification
|
|
||||||
#define SPIFFS_PH_FLAG_FINAL (1<<1)
|
|
||||||
// if 0, this is an index page, else a data page
|
|
||||||
#define SPIFFS_PH_FLAG_INDEX (1<<2)
|
|
||||||
// if 0, page is deleted, else valid
|
|
||||||
#define SPIFFS_PH_FLAG_DELET (1<<7)
|
|
||||||
// if 0, this index header is being deleted
|
|
||||||
#define SPIFFS_PH_FLAG_IXDELE (1<<6)
|
|
||||||
|
|
||||||
|
|
||||||
#define SPIFFS_CHECK_MOUNT(fs) \
|
|
||||||
((fs)->mounted != 0)
|
|
||||||
|
|
||||||
#define SPIFFS_CHECK_CFG(fs) \
|
|
||||||
((fs)->config_magic == SPIFFS_CONFIG_MAGIC)
|
|
||||||
|
|
||||||
#define SPIFFS_CHECK_RES(res) \
|
|
||||||
do { \
|
|
||||||
if ((res) < SPIFFS_OK) return (res); \
|
|
||||||
} while (0);
|
|
||||||
|
|
||||||
#define SPIFFS_API_CHECK_MOUNT(fs) \
|
|
||||||
if (!SPIFFS_CHECK_MOUNT((fs))) { \
|
|
||||||
(fs)->err_code = SPIFFS_ERR_NOT_MOUNTED; \
|
|
||||||
return -1; \
|
|
||||||
}
|
|
||||||
|
|
||||||
#define SPIFFS_API_CHECK_CFG(fs) \
|
|
||||||
if (!SPIFFS_CHECK_CFG((fs))) { \
|
|
||||||
(fs)->err_code = SPIFFS_ERR_NOT_CONFIGURED; \
|
|
||||||
return -1; \
|
|
||||||
}
|
|
||||||
|
|
||||||
#define SPIFFS_API_CHECK_RES(fs, res) \
|
|
||||||
if ((res) < SPIFFS_OK) { \
|
|
||||||
(fs)->err_code = (res); \
|
|
||||||
return -1; \
|
|
||||||
}
|
|
||||||
|
|
||||||
#define SPIFFS_API_CHECK_RES_UNLOCK(fs, res) \
|
|
||||||
if ((res) < SPIFFS_OK) { \
|
|
||||||
(fs)->err_code = (res); \
|
|
||||||
SPIFFS_UNLOCK(fs); \
|
|
||||||
return -1; \
|
|
||||||
}
|
|
||||||
|
|
||||||
#define SPIFFS_VALIDATE_OBJIX(ph, objid, spix) \
|
|
||||||
if (((ph).flags & SPIFFS_PH_FLAG_USED) != 0) return SPIFFS_ERR_IS_FREE; \
|
|
||||||
if (((ph).flags & SPIFFS_PH_FLAG_DELET) == 0) return SPIFFS_ERR_DELETED; \
|
|
||||||
if (((ph).flags & SPIFFS_PH_FLAG_FINAL) != 0) return SPIFFS_ERR_NOT_FINALIZED; \
|
|
||||||
if (((ph).flags & SPIFFS_PH_FLAG_INDEX) != 0) return SPIFFS_ERR_NOT_INDEX; \
|
|
||||||
if (((objid) & SPIFFS_OBJ_ID_IX_FLAG) == 0) return SPIFFS_ERR_NOT_INDEX; \
|
|
||||||
if ((ph).span_ix != (spix)) return SPIFFS_ERR_INDEX_SPAN_MISMATCH;
|
|
||||||
//if ((spix) == 0 && ((ph).flags & SPIFFS_PH_FLAG_IXDELE) == 0) return SPIFFS_ERR_DELETED;
|
|
||||||
|
|
||||||
#define SPIFFS_VALIDATE_DATA(ph, objid, spix) \
|
|
||||||
if (((ph).flags & SPIFFS_PH_FLAG_USED) != 0) return SPIFFS_ERR_IS_FREE; \
|
|
||||||
if (((ph).flags & SPIFFS_PH_FLAG_DELET) == 0) return SPIFFS_ERR_DELETED; \
|
|
||||||
if (((ph).flags & SPIFFS_PH_FLAG_FINAL) != 0) return SPIFFS_ERR_NOT_FINALIZED; \
|
|
||||||
if (((ph).flags & SPIFFS_PH_FLAG_INDEX) == 0) return SPIFFS_ERR_IS_INDEX; \
|
|
||||||
if ((objid) & SPIFFS_OBJ_ID_IX_FLAG) return SPIFFS_ERR_IS_INDEX; \
|
|
||||||
if ((ph).span_ix != (spix)) return SPIFFS_ERR_DATA_SPAN_MISMATCH;
|
|
||||||
|
|
||||||
|
|
||||||
// check id
|
|
||||||
#define SPIFFS_VIS_CHECK_ID (1<<0)
|
|
||||||
// report argument object id to visitor - else object lookup id is reported
|
|
||||||
#define SPIFFS_VIS_CHECK_PH (1<<1)
|
|
||||||
// stop searching at end of all look up pages
|
|
||||||
#define SPIFFS_VIS_NO_WRAP (1<<2)
|
|
||||||
|
|
||||||
#if SPIFFS_HAL_CALLBACK_EXTRA
|
|
||||||
|
|
||||||
#define SPIFFS_HAL_WRITE(_fs, _paddr, _len, _src) \
|
|
||||||
(_fs)->cfg.hal_write_f((_fs), (_paddr), (_len), (_src))
|
|
||||||
#define SPIFFS_HAL_READ(_fs, _paddr, _len, _dst) \
|
|
||||||
(_fs)->cfg.hal_read_f((_fs), (_paddr), (_len), (_dst))
|
|
||||||
#define SPIFFS_HAL_ERASE(_fs, _paddr, _len) \
|
|
||||||
(_fs)->cfg.hal_erase_f((_fs), (_paddr), (_len))
|
|
||||||
|
|
||||||
#else // SPIFFS_HAL_CALLBACK_EXTRA
|
|
||||||
|
|
||||||
#define SPIFFS_HAL_WRITE(_fs, _paddr, _len, _src) \
|
|
||||||
(_fs)->cfg.hal_write_f((_paddr), (_len), (_src))
|
|
||||||
#define SPIFFS_HAL_READ(_fs, _paddr, _len, _dst) \
|
|
||||||
(_fs)->cfg.hal_read_f((_paddr), (_len), (_dst))
|
|
||||||
#define SPIFFS_HAL_ERASE(_fs, _paddr, _len) \
|
|
||||||
(_fs)->cfg.hal_erase_f((_paddr), (_len))
|
|
||||||
|
|
||||||
#endif // SPIFFS_HAL_CALLBACK_EXTRA
|
|
||||||
|
|
||||||
#if SPIFFS_CACHE
|
|
||||||
|
|
||||||
#define SPIFFS_CACHE_FLAG_DIRTY (1<<0)
|
|
||||||
#define SPIFFS_CACHE_FLAG_WRTHRU (1<<1)
|
|
||||||
#define SPIFFS_CACHE_FLAG_OBJLU (1<<2)
|
|
||||||
#define SPIFFS_CACHE_FLAG_OBJIX (1<<3)
|
|
||||||
#define SPIFFS_CACHE_FLAG_DATA (1<<4)
|
|
||||||
#define SPIFFS_CACHE_FLAG_TYPE_WR (1<<7)
|
|
||||||
|
|
||||||
#define SPIFFS_CACHE_PAGE_SIZE(fs) \
|
|
||||||
(sizeof(spiffs_cache_page) + SPIFFS_CFG_LOG_PAGE_SZ(fs))
|
|
||||||
|
|
||||||
#define spiffs_get_cache(fs) \
|
|
||||||
((spiffs_cache *)((fs)->cache))
|
|
||||||
|
|
||||||
#define spiffs_get_cache_page_hdr(fs, c, ix) \
|
|
||||||
((spiffs_cache_page *)(&((c)->cpages[(ix) * SPIFFS_CACHE_PAGE_SIZE(fs)])))
|
|
||||||
|
|
||||||
#define spiffs_get_cache_page(fs, c, ix) \
|
|
||||||
((u8_t *)(&((c)->cpages[(ix) * SPIFFS_CACHE_PAGE_SIZE(fs)])) + sizeof(spiffs_cache_page))
|
|
||||||
|
|
||||||
// cache page struct
|
|
||||||
typedef struct {
|
|
||||||
// cache flags
|
|
||||||
u8_t flags;
|
|
||||||
// cache page index
|
|
||||||
u8_t ix;
|
|
||||||
// last access of this cache page
|
|
||||||
u32_t last_access;
|
|
||||||
union {
|
|
||||||
// type read cache
|
|
||||||
struct {
|
|
||||||
// read cache page index
|
|
||||||
spiffs_page_ix pix;
|
|
||||||
};
|
|
||||||
#if SPIFFS_CACHE_WR
|
|
||||||
// type write cache
|
|
||||||
struct {
|
|
||||||
// write cache
|
|
||||||
spiffs_obj_id obj_id;
|
|
||||||
// offset in cache page
|
|
||||||
u32_t offset;
|
|
||||||
// size of cache page
|
|
||||||
u16_t size;
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
} spiffs_cache_page;
|
|
||||||
|
|
||||||
// cache struct
|
|
||||||
typedef struct {
|
|
||||||
u8_t cpage_count;
|
|
||||||
u32_t last_access;
|
|
||||||
u32_t cpage_use_map;
|
|
||||||
u32_t cpage_use_mask;
|
|
||||||
u8_t *cpages;
|
|
||||||
} spiffs_cache;
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
// spiffs nucleus file descriptor
|
|
||||||
typedef struct {
|
|
||||||
// the filesystem of this descriptor
|
|
||||||
spiffs *fs;
|
|
||||||
// number of file descriptor - if 0, the file descriptor is closed
|
|
||||||
spiffs_file file_nbr;
|
|
||||||
// object id - if SPIFFS_OBJ_ID_ERASED, the file was deleted
|
|
||||||
spiffs_obj_id obj_id;
|
|
||||||
// size of the file
|
|
||||||
u32_t size;
|
|
||||||
// cached object index header page index
|
|
||||||
spiffs_page_ix objix_hdr_pix;
|
|
||||||
// cached offset object index page index
|
|
||||||
spiffs_page_ix cursor_objix_pix;
|
|
||||||
// cached offset object index span index
|
|
||||||
spiffs_span_ix cursor_objix_spix;
|
|
||||||
// current absolute offset
|
|
||||||
u32_t offset;
|
|
||||||
// current file descriptor offset
|
|
||||||
u32_t fdoffset;
|
|
||||||
// fd flags
|
|
||||||
spiffs_flags flags;
|
|
||||||
#if SPIFFS_CACHE_WR
|
|
||||||
spiffs_cache_page *cache_page;
|
|
||||||
#endif
|
|
||||||
} spiffs_fd;
|
|
||||||
|
|
||||||
|
|
||||||
// object structs
|
|
||||||
|
|
||||||
// page header, part of each page except object lookup pages
|
|
||||||
// NB: this is always aligned when the data page is an object index,
|
|
||||||
// as in this case struct spiffs_page_object_ix is used
|
|
||||||
typedef struct __attribute(( packed )) {
|
|
||||||
// object id
|
|
||||||
spiffs_obj_id obj_id;
|
|
||||||
// object span index
|
|
||||||
spiffs_span_ix span_ix;
|
|
||||||
// flags
|
|
||||||
u8_t flags;
|
|
||||||
} spiffs_page_header;
|
|
||||||
|
|
||||||
// object index header page header
|
|
||||||
typedef struct __attribute(( packed ))
|
|
||||||
#if SPIFFS_ALIGNED_OBJECT_INDEX_TABLES
|
|
||||||
__attribute(( aligned(sizeof(spiffs_page_ix)) ))
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
// common page header
|
|
||||||
spiffs_page_header p_hdr;
|
|
||||||
// alignment
|
|
||||||
u8_t _align[4 - ((sizeof(spiffs_page_header)&3)==0 ? 4 : (sizeof(spiffs_page_header)&3))];
|
|
||||||
// size of object
|
|
||||||
u32_t size;
|
|
||||||
// type of object
|
|
||||||
spiffs_obj_type type;
|
|
||||||
// name of object
|
|
||||||
u8_t name[SPIFFS_OBJ_NAME_LEN];
|
|
||||||
} spiffs_page_object_ix_header;
|
|
||||||
|
|
||||||
// object index page header
|
|
||||||
typedef struct __attribute(( packed )) {
|
|
||||||
spiffs_page_header p_hdr;
|
|
||||||
u8_t _align[4 - ((sizeof(spiffs_page_header)&3)==0 ? 4 : (sizeof(spiffs_page_header)&3))];
|
|
||||||
} spiffs_page_object_ix;
|
|
||||||
|
|
||||||
// callback func for object lookup visitor
|
|
||||||
typedef s32_t (*spiffs_visitor_f)(spiffs *fs, spiffs_obj_id id, spiffs_block_ix bix, int ix_entry,
|
|
||||||
const void *user_const_p, void *user_var_p);
|
|
||||||
|
|
||||||
|
|
||||||
#if SPIFFS_CACHE
|
|
||||||
#define _spiffs_rd(fs, op, fh, addr, len, dst) \
|
|
||||||
spiffs_phys_rd((fs), (op), (fh), (addr), (len), (dst))
|
|
||||||
#define _spiffs_wr(fs, op, fh, addr, len, src) \
|
|
||||||
spiffs_phys_wr((fs), (op), (fh), (addr), (len), (src))
|
|
||||||
#else
|
|
||||||
#define _spiffs_rd(fs, op, fh, addr, len, dst) \
|
|
||||||
spiffs_phys_rd((fs), (addr), (len), (dst))
|
|
||||||
#define _spiffs_wr(fs, op, fh, addr, len, src) \
|
|
||||||
spiffs_phys_wr((fs), (addr), (len), (src))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef MIN
|
|
||||||
#define MIN(a,b) ((a) < (b) ? (a) : (b))
|
|
||||||
#endif
|
|
||||||
#ifndef MAX
|
|
||||||
#define MAX(a,b) ((a) > (b) ? (a) : (b))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// ---------------
|
|
||||||
|
|
||||||
s32_t spiffs_phys_rd(
|
|
||||||
spiffs *fs,
|
|
||||||
#if SPIFFS_CACHE
|
|
||||||
u8_t op,
|
|
||||||
spiffs_file fh,
|
|
||||||
#endif
|
|
||||||
u32_t addr,
|
|
||||||
u32_t len,
|
|
||||||
u8_t *dst);
|
|
||||||
|
|
||||||
s32_t spiffs_phys_wr(
|
|
||||||
spiffs *fs,
|
|
||||||
#if SPIFFS_CACHE
|
|
||||||
u8_t op,
|
|
||||||
spiffs_file fh,
|
|
||||||
#endif
|
|
||||||
u32_t addr,
|
|
||||||
u32_t len,
|
|
||||||
u8_t *src);
|
|
||||||
|
|
||||||
s32_t spiffs_phys_cpy(
|
|
||||||
spiffs *fs,
|
|
||||||
spiffs_file fh,
|
|
||||||
u32_t dst,
|
|
||||||
u32_t src,
|
|
||||||
u32_t len);
|
|
||||||
|
|
||||||
s32_t spiffs_phys_count_free_blocks(
|
|
||||||
spiffs *fs);
|
|
||||||
|
|
||||||
s32_t spiffs_obj_lu_find_entry_visitor(
|
|
||||||
spiffs *fs,
|
|
||||||
spiffs_block_ix starting_block,
|
|
||||||
int starting_lu_entry,
|
|
||||||
u8_t flags,
|
|
||||||
spiffs_obj_id obj_id,
|
|
||||||
spiffs_visitor_f v,
|
|
||||||
const void *user_const_p,
|
|
||||||
void *user_var_p,
|
|
||||||
spiffs_block_ix *block_ix,
|
|
||||||
int *lu_entry);
|
|
||||||
|
|
||||||
s32_t spiffs_erase_block(
|
|
||||||
spiffs *fs,
|
|
||||||
spiffs_block_ix bix);
|
|
||||||
|
|
||||||
#if SPIFFS_USE_MAGIC && SPIFFS_USE_MAGIC_LENGTH
|
|
||||||
s32_t spiffs_probe(
|
|
||||||
spiffs_config *cfg);
|
|
||||||
#endif // SPIFFS_USE_MAGIC && SPIFFS_USE_MAGIC_LENGTH
|
|
||||||
|
|
||||||
// ---------------
|
|
||||||
|
|
||||||
s32_t spiffs_obj_lu_scan(
|
|
||||||
spiffs *fs);
|
|
||||||
|
|
||||||
s32_t spiffs_obj_lu_find_free_obj_id(
|
|
||||||
spiffs *fs,
|
|
||||||
spiffs_obj_id *obj_id,
|
|
||||||
const u8_t *conflicting_name);
|
|
||||||
|
|
||||||
s32_t spiffs_obj_lu_find_free(
|
|
||||||
spiffs *fs,
|
|
||||||
spiffs_block_ix starting_block,
|
|
||||||
int starting_lu_entry,
|
|
||||||
spiffs_block_ix *block_ix,
|
|
||||||
int *lu_entry);
|
|
||||||
|
|
||||||
s32_t spiffs_obj_lu_find_id(
|
|
||||||
spiffs *fs,
|
|
||||||
spiffs_block_ix starting_block,
|
|
||||||
int starting_lu_entry,
|
|
||||||
spiffs_obj_id obj_id,
|
|
||||||
spiffs_block_ix *block_ix,
|
|
||||||
int *lu_entry);
|
|
||||||
|
|
||||||
s32_t spiffs_obj_lu_find_id_and_span(
|
|
||||||
spiffs *fs,
|
|
||||||
spiffs_obj_id obj_id,
|
|
||||||
spiffs_span_ix spix,
|
|
||||||
spiffs_page_ix exclusion_pix,
|
|
||||||
spiffs_page_ix *pix);
|
|
||||||
|
|
||||||
s32_t spiffs_obj_lu_find_id_and_span_by_phdr(
|
|
||||||
spiffs *fs,
|
|
||||||
spiffs_obj_id obj_id,
|
|
||||||
spiffs_span_ix spix,
|
|
||||||
spiffs_page_ix exclusion_pix,
|
|
||||||
spiffs_page_ix *pix);
|
|
||||||
|
|
||||||
// ---------------
|
|
||||||
|
|
||||||
s32_t spiffs_page_allocate_data(
|
|
||||||
spiffs *fs,
|
|
||||||
spiffs_obj_id obj_id,
|
|
||||||
spiffs_page_header *ph,
|
|
||||||
u8_t *data,
|
|
||||||
u32_t len,
|
|
||||||
u32_t page_offs,
|
|
||||||
u8_t finalize,
|
|
||||||
spiffs_page_ix *pix);
|
|
||||||
|
|
||||||
s32_t spiffs_page_move(
|
|
||||||
spiffs *fs,
|
|
||||||
spiffs_file fh,
|
|
||||||
u8_t *page_data,
|
|
||||||
spiffs_obj_id obj_id,
|
|
||||||
spiffs_page_header *page_hdr,
|
|
||||||
spiffs_page_ix src_pix,
|
|
||||||
spiffs_page_ix *dst_pix);
|
|
||||||
|
|
||||||
s32_t spiffs_page_delete(
|
|
||||||
spiffs *fs,
|
|
||||||
spiffs_page_ix pix);
|
|
||||||
|
|
||||||
// ---------------
|
|
||||||
|
|
||||||
s32_t spiffs_object_create(
|
|
||||||
spiffs *fs,
|
|
||||||
spiffs_obj_id obj_id,
|
|
||||||
const u8_t name[SPIFFS_OBJ_NAME_LEN],
|
|
||||||
spiffs_obj_type type,
|
|
||||||
spiffs_page_ix *objix_hdr_pix);
|
|
||||||
|
|
||||||
s32_t spiffs_object_update_index_hdr(
|
|
||||||
spiffs *fs,
|
|
||||||
spiffs_fd *fd,
|
|
||||||
spiffs_obj_id obj_id,
|
|
||||||
spiffs_page_ix objix_hdr_pix,
|
|
||||||
u8_t *new_objix_hdr_data,
|
|
||||||
const u8_t name[SPIFFS_OBJ_NAME_LEN],
|
|
||||||
u32_t size,
|
|
||||||
spiffs_page_ix *new_pix);
|
|
||||||
|
|
||||||
void spiffs_cb_object_event(
|
|
||||||
spiffs *fs,
|
|
||||||
spiffs_fd *fd,
|
|
||||||
int ev,
|
|
||||||
spiffs_obj_id obj_id,
|
|
||||||
spiffs_span_ix spix,
|
|
||||||
spiffs_page_ix new_pix,
|
|
||||||
u32_t new_size);
|
|
||||||
|
|
||||||
s32_t spiffs_object_open_by_id(
|
|
||||||
spiffs *fs,
|
|
||||||
spiffs_obj_id obj_id,
|
|
||||||
spiffs_fd *f,
|
|
||||||
spiffs_flags flags,
|
|
||||||
spiffs_mode mode);
|
|
||||||
|
|
||||||
s32_t spiffs_object_open_by_page(
|
|
||||||
spiffs *fs,
|
|
||||||
spiffs_page_ix pix,
|
|
||||||
spiffs_fd *f,
|
|
||||||
spiffs_flags flags,
|
|
||||||
spiffs_mode mode);
|
|
||||||
|
|
||||||
s32_t spiffs_object_append(
|
|
||||||
spiffs_fd *fd,
|
|
||||||
u32_t offset,
|
|
||||||
u8_t *data,
|
|
||||||
u32_t len);
|
|
||||||
|
|
||||||
s32_t spiffs_object_modify(
|
|
||||||
spiffs_fd *fd,
|
|
||||||
u32_t offset,
|
|
||||||
u8_t *data,
|
|
||||||
u32_t len);
|
|
||||||
|
|
||||||
s32_t spiffs_object_read(
|
|
||||||
spiffs_fd *fd,
|
|
||||||
u32_t offset,
|
|
||||||
u32_t len,
|
|
||||||
u8_t *dst);
|
|
||||||
|
|
||||||
s32_t spiffs_object_truncate(
|
|
||||||
spiffs_fd *fd,
|
|
||||||
u32_t new_len,
|
|
||||||
u8_t remove_object);
|
|
||||||
|
|
||||||
s32_t spiffs_object_find_object_index_header_by_name(
|
|
||||||
spiffs *fs,
|
|
||||||
const u8_t name[SPIFFS_OBJ_NAME_LEN],
|
|
||||||
spiffs_page_ix *pix);
|
|
||||||
|
|
||||||
// ---------------
|
|
||||||
|
|
||||||
s32_t spiffs_gc_check(
|
|
||||||
spiffs *fs,
|
|
||||||
u32_t len);
|
|
||||||
|
|
||||||
s32_t spiffs_gc_erase_page_stats(
|
|
||||||
spiffs *fs,
|
|
||||||
spiffs_block_ix bix);
|
|
||||||
|
|
||||||
s32_t spiffs_gc_find_candidate(
|
|
||||||
spiffs *fs,
|
|
||||||
spiffs_block_ix **block_candidate,
|
|
||||||
int *candidate_count,
|
|
||||||
char fs_crammed);
|
|
||||||
|
|
||||||
s32_t spiffs_gc_clean(
|
|
||||||
spiffs *fs,
|
|
||||||
spiffs_block_ix bix);
|
|
||||||
|
|
||||||
s32_t spiffs_gc_quick(
|
|
||||||
spiffs *fs, u16_t max_free_pages);
|
|
||||||
|
|
||||||
// ---------------
|
|
||||||
|
|
||||||
s32_t spiffs_fd_find_new(
|
|
||||||
spiffs *fs,
|
|
||||||
spiffs_fd **fd);
|
|
||||||
|
|
||||||
s32_t spiffs_fd_return(
|
|
||||||
spiffs *fs,
|
|
||||||
spiffs_file f);
|
|
||||||
|
|
||||||
s32_t spiffs_fd_get(
|
|
||||||
spiffs *fs,
|
|
||||||
spiffs_file f,
|
|
||||||
spiffs_fd **fd);
|
|
||||||
|
|
||||||
#if SPIFFS_CACHE
|
|
||||||
void spiffs_cache_init(
|
|
||||||
spiffs *fs);
|
|
||||||
|
|
||||||
void spiffs_cache_drop_page(
|
|
||||||
spiffs *fs,
|
|
||||||
spiffs_page_ix pix);
|
|
||||||
|
|
||||||
#if SPIFFS_CACHE_WR
|
|
||||||
spiffs_cache_page *spiffs_cache_page_allocate_by_fd(
|
|
||||||
spiffs *fs,
|
|
||||||
spiffs_fd *fd);
|
|
||||||
|
|
||||||
void spiffs_cache_fd_release(
|
|
||||||
spiffs *fs,
|
|
||||||
spiffs_cache_page *cp);
|
|
||||||
|
|
||||||
spiffs_cache_page *spiffs_cache_page_get_by_fd(
|
|
||||||
spiffs *fs,
|
|
||||||
spiffs_fd *fd);
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
s32_t spiffs_lookup_consistency_check(
|
|
||||||
spiffs *fs,
|
|
||||||
u8_t check_all_objects);
|
|
||||||
|
|
||||||
s32_t spiffs_page_consistency_check(
|
|
||||||
spiffs *fs);
|
|
||||||
|
|
||||||
s32_t spiffs_object_index_consistency_check(
|
|
||||||
spiffs *fs);
|
|
||||||
|
|
||||||
#endif /* SPIFFS_NUCLEUS_H_ */
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright (c) 2011 Arduino. All right reserved.
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
See the GNU Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \file syscalls.h
|
|
||||||
*
|
|
||||||
* Implementation of newlib syscall.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*----------------------------------------------------------------------------
|
|
||||||
* Headers
|
|
||||||
*----------------------------------------------------------------------------*/
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
|
|
||||||
/*----------------------------------------------------------------------------
|
|
||||||
* Exported functions
|
|
||||||
*----------------------------------------------------------------------------*/
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
extern caddr_t _sbrk( int incr ) ;
|
|
||||||
|
|
||||||
extern int link( char *cOld, char *cNew ) ;
|
|
||||||
|
|
||||||
extern int _close( int file ) ;
|
|
||||||
|
|
||||||
extern int _fstat( int file, struct stat *st ) ;
|
|
||||||
|
|
||||||
extern int _isatty( int file ) ;
|
|
||||||
|
|
||||||
extern int _lseek( int file, int ptr, int dir ) ;
|
|
||||||
|
|
||||||
extern int _read(int file, char *ptr, int len) ;
|
|
||||||
|
|
||||||
extern int _write( int file, char *ptr, int len ) ;
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
@@ -16,107 +16,80 @@
|
|||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "Arduino.h"
|
#include <Arduino.h>
|
||||||
|
#include <cmsis_os.h>
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "cmsis_os.h"
|
|
||||||
|
|
||||||
#ifndef portNVIC_SYSTICK_CURRENT_VALUE_REG
|
#ifndef portNVIC_SYSTICK_CURRENT_VALUE_REG
|
||||||
#define portNVIC_SYSTICK_CURRENT_VALUE_REG ( * ( ( volatile uint32_t * ) 0xe000e018 ) )
|
#define portNVIC_SYSTICK_CURRENT_VALUE_REG (*((volatile uint32_t *)0xe000e018))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern uint32_t xTaskGetTickCount();
|
extern uint32_t xTaskGetTickCount();
|
||||||
extern uint32_t xTaskGetTickCountFromISR();
|
extern uint32_t xTaskGetTickCountFromISR();
|
||||||
|
|
||||||
static __inline uint32_t __get_ipsr__(void)
|
static __inline uint32_t __get_ipsr__(void) {
|
||||||
{
|
volatile uint32_t __regIPSR __asm("ipsr");
|
||||||
volatile uint32_t __regIPSR __asm("ipsr");
|
return (__regIPSR);
|
||||||
return(__regIPSR);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void init(void)
|
void init(void) {
|
||||||
{
|
// nop
|
||||||
// nop
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void delay( uint32_t ms )
|
void delay(uint32_t ms) {
|
||||||
{
|
/* osStatus ret; */
|
||||||
osStatus ret;
|
|
||||||
|
|
||||||
ret = osDelay(ms);
|
/* ret = */ osDelay(ms);
|
||||||
if ( (ret != osEventTimeout) && (ret != osOK) ) {
|
/* if ((ret != osEventTimeout) && (ret != osOK)) {
|
||||||
//printf("delay : ERROR : 0x%x \n", ret);
|
printf("delay : ERROR : 0x%x \n", ret);
|
||||||
|
} */
|
||||||
|
}
|
||||||
|
|
||||||
|
void delayMicroseconds(unsigned int us) {
|
||||||
|
int i;
|
||||||
|
uint32_t t0, tn;
|
||||||
|
int dfactor = 20 * us - 10 + (81 * us / 100);
|
||||||
|
|
||||||
|
if (us > 100) {
|
||||||
|
t0 = micros();
|
||||||
|
do {
|
||||||
|
tn = micros();
|
||||||
|
} while (tn >= t0 && tn < (t0 + us - 1));
|
||||||
|
} else {
|
||||||
|
for (i = 0; i < dfactor; i++) {
|
||||||
|
asm("nop");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void delayMicroseconds(unsigned int us)
|
uint32_t millis(void) {
|
||||||
{
|
return (__get_ipsr__() == 0) ? xTaskGetTickCount() : xTaskGetTickCountFromISR();
|
||||||
int i;
|
|
||||||
uint32_t t0, tn;
|
|
||||||
int dfactor = 0;
|
|
||||||
|
|
||||||
#if defined(BOARD_RTL8710)
|
|
||||||
// dfactor = 10 * us - 10 + (40 * us / 100);
|
|
||||||
dfactor = 20 * us - 10 + (81 * us / 100);
|
|
||||||
#elif defined(BOARD_RTL8195A)
|
|
||||||
dfactor = 20 * us - 10 + (81 * us / 100);
|
|
||||||
#else
|
|
||||||
dfactor = 20 * us - 10 + (81 * us / 100);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if ( us > 100 ) {
|
|
||||||
t0 = micros();
|
|
||||||
do {
|
|
||||||
tn = micros();
|
|
||||||
} while ( tn >= t0 && tn < (t0 + us - 1) );
|
|
||||||
} else {
|
|
||||||
for (i=0; i<dfactor; i++) {
|
|
||||||
asm("nop");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t millis( void )
|
uint32_t micros(void) {
|
||||||
{
|
uint32_t tick1, tick2;
|
||||||
return (__get_ipsr__() == 0) ? xTaskGetTickCount() : xTaskGetTickCountFromISR();
|
uint32_t us;
|
||||||
|
uint32_t tick_per_us = 166666;
|
||||||
|
|
||||||
|
if (__get_ipsr__() == 0) {
|
||||||
|
tick1 = xTaskGetTickCount();
|
||||||
|
us = portNVIC_SYSTICK_CURRENT_VALUE_REG;
|
||||||
|
tick2 = xTaskGetTickCount();
|
||||||
|
} else {
|
||||||
|
tick1 = xTaskGetTickCountFromISR();
|
||||||
|
us = portNVIC_SYSTICK_CURRENT_VALUE_REG;
|
||||||
|
tick2 = xTaskGetTickCountFromISR();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tick1 == tick2) {
|
||||||
|
return tick1 * 1000 - us * 1000 / tick_per_us;
|
||||||
|
} else if ((us * 1000 / tick_per_us) < 500) {
|
||||||
|
return tick1 * 1000 - us * 1000 / tick_per_us;
|
||||||
|
} else {
|
||||||
|
return tick1 * 1000;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t micros( void )
|
void yield(void) {
|
||||||
{
|
vTaskDelay(1);
|
||||||
uint32_t tick1, tick2;
|
taskYIELD();
|
||||||
uint32_t us;
|
|
||||||
uint32_t tick_per_us;
|
|
||||||
|
|
||||||
#if defined(BOARD_RTL8710)
|
|
||||||
tick_per_us = 166666; // 83333;
|
|
||||||
#elif defined(BOARD_RTL8195A)
|
|
||||||
tick_per_us = 166666;
|
|
||||||
#else
|
|
||||||
tick_per_us = 166666;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (__get_ipsr__() == 0) {
|
|
||||||
tick1 = xTaskGetTickCount();
|
|
||||||
us = portNVIC_SYSTICK_CURRENT_VALUE_REG;
|
|
||||||
tick2 = xTaskGetTickCount();
|
|
||||||
} else {
|
|
||||||
tick1 = xTaskGetTickCountFromISR();
|
|
||||||
us = portNVIC_SYSTICK_CURRENT_VALUE_REG;
|
|
||||||
tick2 = xTaskGetTickCountFromISR();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tick1 == tick2) {
|
|
||||||
return tick1 * 1000 - us*1000 / tick_per_us;
|
|
||||||
} else if( (us*1000 / tick_per_us) < 500 ) {
|
|
||||||
return tick1 * 1000 - us*1000 / tick_per_us;
|
|
||||||
} else {
|
|
||||||
return tick1 * 1000;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|||||||
@@ -16,225 +16,190 @@
|
|||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// RTL8710 module do not support ADC/DAC
|
#include <Arduino.h>
|
||||||
#if 1 // !defined(BOARD_RTL8710)
|
#include <analogin_api.h>
|
||||||
|
#include <analogout_api.h>
|
||||||
#include "Arduino.h"
|
#include <gpio_ex_api.h>
|
||||||
|
#include <pwmout_api.h>
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "analogin_api.h"
|
|
||||||
#include "analogout_api.h"
|
|
||||||
#include "pwmout_api.h"
|
|
||||||
#include "gpio_ex_api.h"
|
|
||||||
|
|
||||||
|
|
||||||
/* ADC */
|
/* ADC */
|
||||||
analogin_t adc1;
|
analogin_t adc1;
|
||||||
analogin_t adc2;
|
analogin_t adc2;
|
||||||
analogin_t adc3;
|
analogin_t adc3;
|
||||||
|
|
||||||
static const float ADC_slope1 = (3.12)/(3410.0-674.0);
|
static const float ADC_slope1 = (3.12) / (3410.0 - 674.0);
|
||||||
static const float ADC_slope2 = (3.3-3.12)/(3454.0-3410.0);
|
static const float ADC_slope2 = (3.3 - 3.12) / (3454.0 - 3410.0);
|
||||||
|
|
||||||
bool g_adc_enabled[] = {
|
bool g_adc_enabled[] = {false, false, false};
|
||||||
false, false, false
|
|
||||||
};
|
|
||||||
|
|
||||||
extern void *gpio_pin_struct[];
|
extern void *gpio_pin_struct[];
|
||||||
|
|
||||||
//
|
extern void pinRemoveMode(pin_size_t pinNumber);
|
||||||
// Arduino
|
|
||||||
//
|
|
||||||
|
|
||||||
static int _readResolution = 10;
|
static int _readResolution = 10;
|
||||||
static int _writeResolution = 8;
|
static int _writeResolution = 8;
|
||||||
static int _writePeriod = 20000;
|
static int _writePeriod = 20000;
|
||||||
|
|
||||||
void analogReadResolution(int res) {
|
void analogReadResolution(int res) {
|
||||||
_readResolution = res;
|
_readResolution = res;
|
||||||
}
|
}
|
||||||
|
|
||||||
void analogWriteResolution(int res) {
|
void analogWriteResolution(int res) {
|
||||||
_writeResolution = res;
|
_writeResolution = res;
|
||||||
}
|
}
|
||||||
|
|
||||||
void analogWritePeriod(int us) {
|
void analogWritePeriod(int us) {
|
||||||
_writePeriod = us;
|
_writePeriod = us;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint32_t mapResolution(uint32_t value, uint32_t from, uint32_t to) {
|
static inline uint32_t mapResolution(uint32_t value, uint32_t from, uint32_t to) {
|
||||||
if (from == to)
|
if (from == to)
|
||||||
return value;
|
return value;
|
||||||
if (from > to)
|
if (from > to)
|
||||||
return value >> (from-to);
|
return value >> (from - to);
|
||||||
else
|
else
|
||||||
return value << (to-from);
|
return value << (to - from);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t analog_reference = AR_DEFAULT;
|
uint8_t analog_reference = AR_DEFAULT;
|
||||||
|
|
||||||
void analogReference(uint8_t mode)
|
void analogReference(uint8_t mode) {
|
||||||
{
|
analog_reference = mode;
|
||||||
analog_reference = mode;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int analogRead(pin_size_t pinNumber)
|
int analogRead(pin_size_t pinNumber) {
|
||||||
{
|
uint32_t ulValue = 0;
|
||||||
uint32_t ulValue = 0;
|
uint32_t ulChannel;
|
||||||
uint32_t ulChannel;
|
uint16_t ret = 0;
|
||||||
uint16_t ret = 0;
|
float voltage;
|
||||||
float voltage;
|
float adc_value;
|
||||||
float adc_value;
|
|
||||||
|
|
||||||
switch ( pinNumber ) {
|
switch (pinNumber) {
|
||||||
case PIN_A0:
|
case PIN_A0:
|
||||||
if (g_adc_enabled[0] == false)
|
if (g_adc_enabled[0] == false) {
|
||||||
{
|
analogin_init(&adc1, AD_1);
|
||||||
analogin_init(&adc1, AD_1);
|
g_adc_enabled[0] = true;
|
||||||
g_adc_enabled[0] = true;
|
}
|
||||||
}
|
case PIN_A1:
|
||||||
case PIN_A1:
|
if (g_adc_enabled[1] == false) {
|
||||||
if (g_adc_enabled[1] == false)
|
analogin_init(&adc2, AD_2);
|
||||||
{
|
g_adc_enabled[1] = true;
|
||||||
analogin_init(&adc2, AD_2);
|
}
|
||||||
g_adc_enabled[1] = true;
|
ret = analogin_read_u16(&adc2);
|
||||||
}
|
break;
|
||||||
ret = analogin_read_u16(&adc2);
|
case PIN_A2:
|
||||||
break;
|
if (g_adc_enabled[2] == false) {
|
||||||
case PIN_A2:
|
analogin_init(&adc3, AD_3);
|
||||||
if (g_adc_enabled[2] == false)
|
g_adc_enabled[2] = true;
|
||||||
{
|
}
|
||||||
analogin_init(&adc3, AD_3);
|
ret = analogin_read_u16(&adc3);
|
||||||
g_adc_enabled[2] = true;
|
break;
|
||||||
}
|
default:
|
||||||
ret = analogin_read_u16(&adc3);
|
printf("%s : pinNumber %d wrong\n", __FUNCTION__, pinNumber);
|
||||||
break;
|
return 0;
|
||||||
default:
|
}
|
||||||
printf("%s : pinNumber %d wrong\n", __FUNCTION__, pinNumber);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret >>= 4;
|
ret >>= 4;
|
||||||
if (ret < 674) {
|
if (ret < 674) {
|
||||||
voltage = 0;
|
voltage = 0;
|
||||||
} else if ( ret > 3410){
|
} else if (ret > 3410) {
|
||||||
voltage = (float)(ret - 3410)*ADC_slope2 + 3.12;
|
voltage = (float)(ret - 3410) * ADC_slope2 + 3.12;
|
||||||
} else {
|
} else {
|
||||||
voltage = (float)(ret-674)*ADC_slope1;
|
voltage = (float)(ret - 674) * ADC_slope1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = round((1<<_readResolution)*voltage/3.3);
|
|
||||||
if ( ret >= (1<<_readResolution) ) ret = (1<<_readResolution) - 1;
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
|
ret = round((1 << _readResolution) * voltage / 3.3);
|
||||||
|
if (ret >= (1 << _readResolution))
|
||||||
|
ret = (1 << _readResolution) - 1;
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void analogOutputInit(void) {
|
void analogOutputInit(void) {
|
||||||
// nop
|
// nop
|
||||||
}
|
}
|
||||||
|
|
||||||
// Right now, PWM output only works on the pins with
|
// Right now, PWM output only works on the pins with
|
||||||
// hardware support. These are defined in the appropriate
|
// hardware support. These are defined in the appropriate
|
||||||
// pins_*.c file. For the rest of the pins, we default
|
// pins_*.c file. For the rest of the pins, we default
|
||||||
// to digital output.
|
// to digital output.
|
||||||
void analogWrite(pin_size_t pinNumber, int value)
|
void analogWrite(pin_size_t pinNumber, int value) {
|
||||||
{
|
pwmout_t *obj;
|
||||||
pwmout_t *obj;
|
|
||||||
|
|
||||||
if ((g_APinDescription[pinNumber].ulPinAttribute & PIO_PWM) == PIO_PWM) {
|
if ((g_APinDescription[pinNumber].ulPinAttribute & PIO_PWM) == PIO_PWM) {
|
||||||
/* Handle */
|
/* Handle */
|
||||||
if ( g_APinDescription[pinNumber].ulPinType != PIO_PWM )
|
if (g_APinDescription[pinNumber].ulPinType != PIO_PWM) {
|
||||||
{
|
if ((g_APinDescription[pinNumber].ulPinType == PIO_GPIO) ||
|
||||||
if ( (g_APinDescription[pinNumber].ulPinType == PIO_GPIO) || (g_APinDescription[pinNumber].ulPinType == PIO_GPIO_IRQ) ) {
|
(g_APinDescription[pinNumber].ulPinType == PIO_GPIO_IRQ)) {
|
||||||
pinRemoveMode(pinNumber);
|
pinRemoveMode(pinNumber);
|
||||||
}
|
}
|
||||||
gpio_pin_struct[pinNumber] = malloc ( sizeof(pwmout_t) );
|
gpio_pin_struct[pinNumber] = malloc(sizeof(pwmout_t));
|
||||||
pwmout_t *obj = (pwmout_t *)gpio_pin_struct[pinNumber];
|
pwmout_t *obj = (pwmout_t *)gpio_pin_struct[pinNumber];
|
||||||
pwmout_init( obj, g_APinDescription[pinNumber].pinname );
|
pwmout_init(obj, g_APinDescription[pinNumber].pinname);
|
||||||
pwmout_period_us( obj, _writePeriod);
|
pwmout_period_us(obj, _writePeriod);
|
||||||
pwmout_write( obj, value * 1.0 / (1<<_writeResolution));
|
pwmout_write(obj, value * 1.0 / (1 << _writeResolution));
|
||||||
g_APinDescription[pinNumber].ulPinType = PIO_PWM;
|
g_APinDescription[pinNumber].ulPinType = PIO_PWM;
|
||||||
g_APinDescription[pinNumber].ulPinMode = PWM_MODE_ENABLED;
|
g_APinDescription[pinNumber].ulPinMode = PWM_MODE_ENABLED;
|
||||||
} else {
|
} else {
|
||||||
pwmout_t *obj = (pwmout_t *)gpio_pin_struct[pinNumber];
|
pwmout_t *obj = (pwmout_t *)gpio_pin_struct[pinNumber];
|
||||||
pwmout_period_us( obj, _writePeriod);
|
pwmout_period_us(obj, _writePeriod);
|
||||||
pwmout_write( obj, value * 1.0 / (1<<_writeResolution));
|
pwmout_write(obj, value * 1.0 / (1 << _writeResolution));
|
||||||
/* if ( g_APinDescription[pinNumber].ulPinMode == PWM_MODE_DISABLED ) {
|
/* if ( g_APinDescription[pinNumber].ulPinMode == PWM_MODE_DISABLED ) {
|
||||||
HAL_Pwm_Enable( &obj->pwm_hal_adp );
|
HAL_Pwm_Enable( &obj->pwm_hal_adp );
|
||||||
} */
|
} */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct _tone_argument {
|
typedef struct _tone_argument {
|
||||||
uint32_t ulPin;
|
uint32_t ulPin;
|
||||||
uint32_t timer_id;
|
uint32_t timer_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
void _tone_timer_handler(void const *argument)
|
void _tone_timer_handler(const void *argument) {
|
||||||
{
|
struct _tone_argument *arg = (struct _tone_argument *)argument;
|
||||||
struct _tone_argument *arg = (struct _tone_argument *)argument;
|
|
||||||
|
|
||||||
uint32_t ulPin = (uint32_t) argument;
|
uint32_t ulPin = (uint32_t)argument;
|
||||||
|
|
||||||
noTone(arg->ulPin);
|
noTone(arg->ulPin);
|
||||||
|
|
||||||
os_timer_delete(arg->timer_id);
|
os_timer_delete(arg->timer_id);
|
||||||
|
|
||||||
free( (struct _tone_argument *) arg );
|
free((struct _tone_argument *)arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _tone(uint32_t ulPin, unsigned int frequency, unsigned long duration)
|
void _tone(uint32_t ulPin, unsigned int frequency, unsigned long duration) {
|
||||||
{
|
pwmout_t *obj;
|
||||||
pwmout_t *obj;
|
|
||||||
|
|
||||||
if ((g_APinDescription[ulPin].ulPinAttribute & PIO_PWM) != PIO_PWM) {
|
if ((g_APinDescription[ulPin].ulPinAttribute & PIO_PWM) != PIO_PWM) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( g_APinDescription[ulPin].ulPinType != PIO_PWM )
|
if (g_APinDescription[ulPin].ulPinType != PIO_PWM) {
|
||||||
{
|
if ((g_APinDescription[ulPin].ulPinType == PIO_GPIO) || (g_APinDescription[ulPin].ulPinType == PIO_GPIO_IRQ)) {
|
||||||
if ( (g_APinDescription[ulPin].ulPinType == PIO_GPIO) || (g_APinDescription[ulPin].ulPinType == PIO_GPIO_IRQ) ) {
|
pinRemoveMode(ulPin);
|
||||||
pinRemoveMode(ulPin);
|
}
|
||||||
}
|
gpio_pin_struct[ulPin] = malloc(sizeof(pwmout_t));
|
||||||
gpio_pin_struct[ulPin] = malloc ( sizeof(pwmout_t) );
|
pwmout_t *obj = (pwmout_t *)gpio_pin_struct[ulPin];
|
||||||
pwmout_t *obj = (pwmout_t *)gpio_pin_struct[ulPin];
|
pwmout_init(obj, g_APinDescription[ulPin].pinname);
|
||||||
pwmout_init( obj, g_APinDescription[ulPin].pinname);
|
pwmout_period(obj, 1.0 / frequency);
|
||||||
pwmout_period( obj, 1.0/frequency );
|
pwmout_pulsewidth(obj, 1.0 / (frequency * 2));
|
||||||
pwmout_pulsewidth( obj, 1.0/(frequency * 2) );
|
g_APinDescription[ulPin].ulPinType = PIO_PWM;
|
||||||
g_APinDescription[ulPin].ulPinType = PIO_PWM;
|
g_APinDescription[ulPin].ulPinMode = PWM_MODE_ENABLED;
|
||||||
g_APinDescription[ulPin].ulPinMode = PWM_MODE_ENABLED;
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// There is already a PWM configured
|
// There is already a PWM configured
|
||||||
pwmout_t *obj = (pwmout_t *)gpio_pin_struct[ulPin];
|
pwmout_t *obj = (pwmout_t *)gpio_pin_struct[ulPin];
|
||||||
pwmout_period( obj, 1.0/frequency );
|
pwmout_period(obj, 1.0 / frequency);
|
||||||
pwmout_pulsewidth( obj, 1.0/(frequency * 2));
|
pwmout_pulsewidth(obj, 1.0 / (frequency * 2));
|
||||||
/* if (g_APinDescription[ulPin].ulPinMode == PWM_MODE_DISABLED) {
|
/* if (g_APinDescription[ulPin].ulPinMode == PWM_MODE_DISABLED) {
|
||||||
HAL_Pwm_Enable( &obj->pwm_hal_adp );
|
HAL_Pwm_Enable( &obj->pwm_hal_adp );
|
||||||
} */
|
} */
|
||||||
}
|
}
|
||||||
|
|
||||||
if (duration > 0) {
|
if (duration > 0) {
|
||||||
struct _tone_argument *arg = (struct _tone_argument *) malloc ( sizeof(struct _tone_argument) );
|
struct _tone_argument *arg = (struct _tone_argument *)malloc(sizeof(struct _tone_argument));
|
||||||
arg->ulPin = ulPin;
|
arg->ulPin = ulPin;
|
||||||
arg->timer_id = os_timer_create(_tone_timer_handler, 0, arg);
|
arg->timer_id = os_timer_create(_tone_timer_handler, 0, arg);
|
||||||
os_timer_start(arg->timer_id, duration);
|
os_timer_start(arg->timer_id, duration);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void noTone(uint32_t ulPin)
|
|
||||||
{
|
|
||||||
pinRemoveMode(ulPin);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//#else // #if !defined(BOARD_RTL8710)
|
|
||||||
|
|
||||||
#endif // #if !defined(BOARD_RTL8710)
|
|
||||||
|
|||||||
@@ -1,13 +1,8 @@
|
|||||||
#include "Arduino.h"
|
#include <Arduino.h>
|
||||||
|
#include <gpio_api.h>
|
||||||
#ifdef __cplusplus
|
#include <gpio_irq_api.h>
|
||||||
extern "C" {
|
#include <gpio_irq_ex_api.h>
|
||||||
#endif
|
#include <pwmout_api.h>
|
||||||
|
|
||||||
#include "gpio_api.h"
|
|
||||||
#include "gpio_irq_api.h"
|
|
||||||
#include "gpio_irq_ex_api.h"
|
|
||||||
#include "pwmout_api.h"
|
|
||||||
|
|
||||||
extern void *gpio_pin_struct[PINS_COUNT];
|
extern void *gpio_pin_struct[PINS_COUNT];
|
||||||
extern void *gpio_irq_handler_list[PINS_COUNT];
|
extern void *gpio_irq_handler_list[PINS_COUNT];
|
||||||
@@ -33,7 +28,7 @@ void pinRemoveMode(pin_size_t pinNumber) {
|
|||||||
gpio_irq_deinit(obj);
|
gpio_irq_deinit(obj);
|
||||||
free(obj);
|
free(obj);
|
||||||
}
|
}
|
||||||
gpio_pin_struct[pinNumber] = NULL;
|
gpio_pin_struct[pinNumber] = NULL;
|
||||||
g_APinDescription[pinNumber].ulPinType = NOT_INITIAL;
|
g_APinDescription[pinNumber].ulPinType = NOT_INITIAL;
|
||||||
g_APinDescription[pinNumber].ulPinMode = NOT_INITIAL;
|
g_APinDescription[pinNumber].ulPinMode = NOT_INITIAL;
|
||||||
}
|
}
|
||||||
@@ -59,7 +54,7 @@ void pinMode(pin_size_t pinNumber, PinModeArduino pinMode) {
|
|||||||
|
|
||||||
if (g_APinDescription[pinNumber].ulPinType == NOT_INITIAL) {
|
if (g_APinDescription[pinNumber].ulPinType == NOT_INITIAL) {
|
||||||
// allocate memory if pin not used before
|
// allocate memory if pin not used before
|
||||||
gpio = malloc(sizeof(gpio_t));
|
gpio = malloc(sizeof(gpio_t));
|
||||||
gpio_pin_struct[pinNumber] = gpio;
|
gpio_pin_struct[pinNumber] = gpio;
|
||||||
gpio_init(gpio, g_APinDescription[pinNumber].pinname);
|
gpio_init(gpio, g_APinDescription[pinNumber].pinname);
|
||||||
g_APinDescription[pinNumber].ulPinType = PIO_GPIO;
|
g_APinDescription[pinNumber].ulPinType = PIO_GPIO;
|
||||||
@@ -74,23 +69,23 @@ void pinMode(pin_size_t pinNumber, PinModeArduino pinMode) {
|
|||||||
|
|
||||||
switch (pinMode) {
|
switch (pinMode) {
|
||||||
case INPUT:
|
case INPUT:
|
||||||
dir = PIN_INPUT;
|
dir = PIN_INPUT;
|
||||||
mode = PullNone;
|
mode = PullNone;
|
||||||
break;
|
break;
|
||||||
case INPUT_PULLDOWN:
|
case INPUT_PULLDOWN:
|
||||||
dir = PIN_INPUT;
|
dir = PIN_INPUT;
|
||||||
mode = PullDown;
|
mode = PullDown;
|
||||||
break;
|
break;
|
||||||
case INPUT_PULLUP:
|
case INPUT_PULLUP:
|
||||||
dir = PIN_INPUT;
|
dir = PIN_INPUT;
|
||||||
mode = PullUp;
|
mode = PullUp;
|
||||||
break;
|
break;
|
||||||
case OUTPUT:
|
case OUTPUT:
|
||||||
dir = PIN_OUTPUT;
|
dir = PIN_OUTPUT;
|
||||||
mode = PullNone;
|
mode = PullNone;
|
||||||
break;
|
break;
|
||||||
case OUTPUT_OPENDRAIN:
|
case OUTPUT_OPENDRAIN:
|
||||||
dir = PIN_OUTPUT;
|
dir = PIN_OUTPUT;
|
||||||
mode = OpenDrain;
|
mode = OpenDrain;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -138,7 +133,3 @@ uint32_t digitalPinToBitMask(uint32_t pinNumber) {
|
|||||||
uint32_t pin_name = HAL_GPIO_GetPinName(g_APinDescription[pinNumber].pinname);
|
uint32_t pin_name = HAL_GPIO_GetPinName(g_APinDescription[pinNumber].pinname);
|
||||||
return 1 << (HAL_GPIO_GET_PIN_BY_NAME(pin_name));
|
return 1 << (HAL_GPIO_GET_PIN_BY_NAME(pin_name));
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|||||||
@@ -1,118 +0,0 @@
|
|||||||
#include "Arduino.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "wiring_os.h"
|
|
||||||
#include "cmsis_os.h"
|
|
||||||
|
|
||||||
uint32_t os_thread_create( void (*task)(const void *argument), void *argument, int priority, uint32_t stack_size ) {
|
|
||||||
|
|
||||||
osThreadDef_t thread_def;
|
|
||||||
|
|
||||||
thread_def.pthread = task;
|
|
||||||
thread_def.tpriority = (osPriority)priority;
|
|
||||||
// the underlying freertos implementation on cmsis os divide stack size by 4
|
|
||||||
thread_def.stacksize = stack_size * 4;
|
|
||||||
thread_def.name = "ARDUINO";
|
|
||||||
|
|
||||||
return (uint32_t)osThreadCreate(&thread_def, argument);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t os_thread_get_id( void ) {
|
|
||||||
return osThreadGetId();
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t os_thread_terminate( uint32_t thread_id ) {
|
|
||||||
return (uint32_t)osThreadTerminate(thread_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t os_thread_yield( void ) {
|
|
||||||
return (uint32_t)osThreadYield();
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t os_thread_set_priority( uint32_t thread_id, int priority ) {
|
|
||||||
return (uint32_t)osThreadSetPriority(thread_id, (osPriority)priority);
|
|
||||||
}
|
|
||||||
|
|
||||||
int os_thread_get_priority( uint32_t thread_id ) {
|
|
||||||
return (int)osThreadGetPriority(thread_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t os_signal_set( uint32_t thread_id, int32_t signals ) {
|
|
||||||
return osSignalSet(thread_id, signals);
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t os_signal_clear( uint32_t thread_id, int32_t signals ) {
|
|
||||||
return osSignalClear(thread_id, signals);
|
|
||||||
}
|
|
||||||
|
|
||||||
os_event_t os_signal_wait( int32_t signals, uint32_t millisec ) {
|
|
||||||
|
|
||||||
osEvent evt;
|
|
||||||
os_event_t ret;
|
|
||||||
|
|
||||||
evt = osSignalWait(signals, millisec);
|
|
||||||
ret.status = (uint32_t)evt.status;
|
|
||||||
ret.value.signals = evt.value.signals;
|
|
||||||
ret.def.message_id = evt.def.message_id;
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef void (*os_ptimer) (void const *argument);
|
|
||||||
|
|
||||||
uint32_t os_timer_create(void (*callback)(void const *argument), uint8_t isPeriodic, void *argument) {
|
|
||||||
|
|
||||||
osTimerDef_t *pTimerDef;
|
|
||||||
|
|
||||||
pTimerDef = (osTimerDef_t *) malloc ( sizeof(osTimerDef_t) );
|
|
||||||
pTimerDef->ptimer = callback;
|
|
||||||
pTimerDef->custom = (struct os_timer_custom *) malloc ( sizeof (struct os_timer_custom) );
|
|
||||||
|
|
||||||
return osTimerCreate(pTimerDef, (isPeriodic ? osTimerPeriodic : osTimerOnce), argument);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t os_timer_start (uint32_t timer_id, uint32_t millisec) {
|
|
||||||
return osTimerStart (timer_id, millisec);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t os_timer_stop (uint32_t timer_id) {
|
|
||||||
return osTimerStop(timer_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t os_timer_delete(uint32_t timer_id) {
|
|
||||||
|
|
||||||
osTimerDef_t *pTimerDef;
|
|
||||||
|
|
||||||
pTimerDef = (osTimerDef_t *) pvTimerGetTimerID(timer_id);
|
|
||||||
free (pTimerDef->custom);
|
|
||||||
free (pTimerDef);
|
|
||||||
|
|
||||||
return osTimerDelete(timer_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t os_semaphore_create(int32_t count) {
|
|
||||||
return (uint32_t)osSemaphoreCreate(NULL, count);
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t os_semaphore_wait(uint32_t semaphore_id, uint32_t millisec) {
|
|
||||||
if (osSemaphoreWait((osSemaphoreId)semaphore_id, millisec) == 0) {
|
|
||||||
return 1;
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t os_semaphore_release(uint32_t semaphore_id) {
|
|
||||||
return (uint32_t)osSemaphoreRelease((osSemaphoreId)semaphore_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t os_semaphore_delete(uint32_t semaphore_id) {
|
|
||||||
return (uint32_t)osSemaphoreDelete((osSemaphoreId)semaphore_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
This library is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
See the GNU Lesser General Public License for more details.
|
See the GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
@@ -16,16 +16,11 @@
|
|||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "Arduino.h"
|
#include <Arduino.h>
|
||||||
|
#include <PinNames.h>
|
||||||
#ifdef __cplusplus
|
#include <gpio_api.h>
|
||||||
extern "C" {
|
#include <objects.h>
|
||||||
#endif
|
#include <us_ticker_api.h>
|
||||||
|
|
||||||
#include "PinNames.h"
|
|
||||||
#include "objects.h"
|
|
||||||
#include "gpio_api.h"
|
|
||||||
#include "us_ticker_api.h"
|
|
||||||
|
|
||||||
extern void *gpio_pin_struct[];
|
extern void *gpio_pin_struct[];
|
||||||
|
|
||||||
@@ -33,8 +28,7 @@ extern void *gpio_pin_struct[];
|
|||||||
* or LOW, the type of pulse to measure. Works on pulses from 2-3 microseconds
|
* or LOW, the type of pulse to measure. Works on pulses from 2-3 microseconds
|
||||||
* to 3 minutes in length, but must be called at least a few dozen microseconds
|
* to 3 minutes in length, but must be called at least a few dozen microseconds
|
||||||
* before the start of the pulse. */
|
* before the start of the pulse. */
|
||||||
extern unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout)
|
extern unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout) {
|
||||||
{
|
|
||||||
// cache the port and bit of the pin in order to speed up the
|
// cache the port and bit of the pin in order to speed up the
|
||||||
// pulse width measuring loop and achieve finer resolution. calling
|
// pulse width measuring loop and achieve finer resolution. calling
|
||||||
// digitalRead() instead yields much coarser resolution.
|
// digitalRead() instead yields much coarser resolution.
|
||||||
@@ -42,12 +36,12 @@ extern unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout)
|
|||||||
|
|
||||||
uint32_t start_ticks, cur_ticks;
|
uint32_t start_ticks, cur_ticks;
|
||||||
|
|
||||||
if ( pin < 0 || pin > PINS_COUNT || (g_APinDescription[pin].pinname == NC) ) return 0;
|
if (pin < 0 || pin > PINS_COUNT || (g_APinDescription[pin].pinname == NC))
|
||||||
|
return 0;
|
||||||
|
|
||||||
/* Handle */
|
/* Handle */
|
||||||
if ( g_APinDescription[pin].ulPinType != PIO_GPIO )
|
if (g_APinDescription[pin].ulPinType != PIO_GPIO) {
|
||||||
{
|
return 0;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pGpio_t = (gpio_t *)gpio_pin_struct[pin];
|
pGpio_t = (gpio_t *)gpio_pin_struct[pin];
|
||||||
@@ -56,20 +50,23 @@ extern unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout)
|
|||||||
start_ticks = us_ticker_read();
|
start_ticks = us_ticker_read();
|
||||||
while (gpio_read(pGpio_t) == state) {
|
while (gpio_read(pGpio_t) == state) {
|
||||||
cur_ticks = us_ticker_read();
|
cur_ticks = us_ticker_read();
|
||||||
if ( cur_ticks - start_ticks > timeout ) return 0;
|
if (cur_ticks - start_ticks > timeout)
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// wait for the pulse to start
|
// wait for the pulse to start
|
||||||
while (gpio_read(pGpio_t) != state) {
|
while (gpio_read(pGpio_t) != state) {
|
||||||
cur_ticks = us_ticker_read();
|
cur_ticks = us_ticker_read();
|
||||||
if ( cur_ticks - start_ticks > timeout ) return 0;
|
if (cur_ticks - start_ticks > timeout)
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// wait for the pulse to stop
|
// wait for the pulse to stop
|
||||||
start_ticks = us_ticker_read();
|
start_ticks = us_ticker_read();
|
||||||
while (gpio_read(pGpio_t) == state) {
|
while (gpio_read(pGpio_t) == state) {
|
||||||
cur_ticks = us_ticker_read();
|
cur_ticks = us_ticker_read();
|
||||||
if ( cur_ticks - start_ticks > timeout ) return 0;
|
if (cur_ticks - start_ticks > timeout)
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
cur_ticks = us_ticker_read();
|
cur_ticks = us_ticker_read();
|
||||||
@@ -80,7 +77,3 @@ extern unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout)
|
|||||||
// the interrupt handlers.
|
// the interrupt handlers.
|
||||||
return cur_ticks - start_ticks;
|
return cur_ticks - start_ticks;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright (c) 2011 Arduino. All right reserved.
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
See the GNU Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "Arduino.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C"{
|
|
||||||
#endif
|
|
||||||
|
|
||||||
uint8_t shiftIn(pin_size_t dataPin, pin_size_t clockPin, BitOrder bitOrder)
|
|
||||||
{
|
|
||||||
uint8_t value = 0 ;
|
|
||||||
uint8_t i ;
|
|
||||||
|
|
||||||
for ( i=0 ; i < 8 ; ++i )
|
|
||||||
{
|
|
||||||
digitalWrite( dataPin, HIGH ) ;
|
|
||||||
|
|
||||||
if ( bitOrder == LSBFIRST )
|
|
||||||
{
|
|
||||||
value |= digitalRead( dataPin ) << i ;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
value |= digitalRead( dataPin ) << (7 - i) ;
|
|
||||||
}
|
|
||||||
|
|
||||||
digitalWrite( clockPin, LOW ) ;
|
|
||||||
}
|
|
||||||
|
|
||||||
return value ;
|
|
||||||
}
|
|
||||||
|
|
||||||
void shiftOut(pin_size_t dataPin, pin_size_t clockPin, BitOrder bitOrder, uint8_t val)
|
|
||||||
{
|
|
||||||
uint8_t i ;
|
|
||||||
|
|
||||||
for ( i=0 ; i < 8 ; i++ )
|
|
||||||
{
|
|
||||||
if ( bitOrder == LSBFIRST )
|
|
||||||
{
|
|
||||||
digitalWrite( dataPin, !!(val & (1 << i)) ) ;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
digitalWrite( dataPin, !!(val & (1 << (7 - i))) ) ;
|
|
||||||
}
|
|
||||||
|
|
||||||
digitalWrite( clockPin, HIGH ) ;
|
|
||||||
digitalWrite( clockPin, LOW ) ;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
} // extern "C"
|
|
||||||
#endif
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
#include "Arduino.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "wdt_api.h"
|
|
||||||
|
|
||||||
extern uint32_t ConfigDebugErr;
|
|
||||||
|
|
||||||
void wdt_reset() {
|
|
||||||
watchdog_refresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
void wdt_enable(uint32_t timeout_ms) {
|
|
||||||
|
|
||||||
uint32_t backup_ConfigDebugErr;
|
|
||||||
|
|
||||||
backup_ConfigDebugErr = ConfigDebugErr;
|
|
||||||
ConfigDebugErr = 0x00000000;
|
|
||||||
|
|
||||||
if (timeout_ms > 8000) {
|
|
||||||
timeout_ms = 8000;
|
|
||||||
}
|
|
||||||
watchdog_init(timeout_ms);
|
|
||||||
watchdog_start();
|
|
||||||
|
|
||||||
ConfigDebugErr = backup_ConfigDebugErr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void wdt_disable() {
|
|
||||||
watchdog_stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
} // extern "C"
|
|
||||||
#endif
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
/** @file wiring_watchdog.h */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @defgroup wiring_watchdog wiring_watchdog
|
|
||||||
* watchdog is used for reboot system when device hang
|
|
||||||
* @{
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _WIRING_WATCHDOG_H_
|
|
||||||
#define _WIRING_WATCHDOG_H_
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/** @defgroup watchdog */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ingroup watchdog
|
|
||||||
* Feed watchdog to avoid it barks
|
|
||||||
*/
|
|
||||||
extern void wdt_reset();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ingroup watchdog
|
|
||||||
* @brief Enable watchdog
|
|
||||||
*
|
|
||||||
* After enbling watchdog, user defined code needs to reset it before watchdog barks. Otherwise it would make system reboot.
|
|
||||||
*
|
|
||||||
* @param[in] timeout_ms The timeout value that watchdog barks. The maximum value is 8 seconds.
|
|
||||||
*/
|
|
||||||
extern void wdt_enable(uint32_t timeout_ms);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ingroup watchdog
|
|
||||||
* Disable watchdog
|
|
||||||
*/
|
|
||||||
extern void wdt_disable();
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* _WIRING_WATCHDOG_H_ */
|
|
||||||
|
|
||||||
/** @} */ // end of group wiring_watchdog
|
|
||||||
@@ -1,98 +0,0 @@
|
|||||||
/*
|
|
||||||
wl_definitions.h - Library for Arduino Wifi shield.
|
|
||||||
Copyright (c) 2011-2014 Arduino. All right reserved.
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
* wl_definitions.h
|
|
||||||
*
|
|
||||||
* Created on: Mar 6, 2011
|
|
||||||
* Author: dlafauci
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef WL_DEFINITIONS_H_
|
|
||||||
#define WL_DEFINITIONS_H_
|
|
||||||
|
|
||||||
// Maximum size of a SSID
|
|
||||||
#define WL_SSID_MAX_LENGTH 32
|
|
||||||
// Length of passphrase. Valid lengths are 8-63.
|
|
||||||
#define WL_WPA_KEY_MAX_LENGTH 63
|
|
||||||
// Length of key in bytes. Valid values are 5 and 13.
|
|
||||||
#define WL_WEP_KEY_MAX_LENGTH 13
|
|
||||||
// Size of a MAC-address or BSSID
|
|
||||||
#define WL_MAC_ADDR_LENGTH 6
|
|
||||||
// Size of a MAC-address or BSSID
|
|
||||||
#define WL_IPV4_LENGTH 4
|
|
||||||
// Maximum size of a SSID list
|
|
||||||
#define WL_NETWORKS_LIST_MAXNUM 50
|
|
||||||
// Maxmium number of socket
|
|
||||||
#define MAX_SOCK_NUM 4
|
|
||||||
// Socket not available constant
|
|
||||||
#define SOCK_NOT_AVAIL 255
|
|
||||||
// Default state value for Wifi state field
|
|
||||||
#define NA_STATE -1
|
|
||||||
//Maximum number of attempts to establish wifi connection
|
|
||||||
#define WL_MAX_ATTEMPT_CONNECTION 10
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
WL_NO_SHIELD = 255,
|
|
||||||
WL_IDLE_STATUS = 0,
|
|
||||||
WL_NO_SSID_AVAIL,
|
|
||||||
WL_SCAN_COMPLETED,
|
|
||||||
WL_CONNECTED,
|
|
||||||
WL_CONNECT_FAILED,
|
|
||||||
WL_CONNECTION_LOST,
|
|
||||||
WL_DISCONNECTED
|
|
||||||
} wl_status_t;
|
|
||||||
|
|
||||||
/* Encryption modes */
|
|
||||||
enum wl_enc_type { /* Values map to 802.11 encryption suites... */
|
|
||||||
ENC_TYPE_WEP = 5,
|
|
||||||
ENC_TYPE_TKIP = 2,
|
|
||||||
ENC_TYPE_CCMP = 4,
|
|
||||||
/* ... except these two, 7 and 8 are reserved in 802.11-2007 */
|
|
||||||
ENC_TYPE_NONE = 7,
|
|
||||||
ENC_TYPE_AUTO = 8
|
|
||||||
};
|
|
||||||
|
|
||||||
/* RTK added type */
|
|
||||||
#ifndef WEP_ENABLED
|
|
||||||
|
|
||||||
#define WEP_ENABLED 0x0001
|
|
||||||
#define TKIP_ENABLED 0x0002
|
|
||||||
#define AES_ENABLED 0x0004
|
|
||||||
#define WSEC_SWFLAG 0x0008
|
|
||||||
|
|
||||||
#define SHARED_ENABLED 0x00008000
|
|
||||||
#define WPA_SECURITY 0x00200000
|
|
||||||
#define WPA2_SECURITY 0x00400000
|
|
||||||
#define WPS_ENABLED 0x10000000
|
|
||||||
|
|
||||||
#endif // #ifndef WEP_ENABLED
|
|
||||||
|
|
||||||
/* redefined from enum rtw_security_t */
|
|
||||||
#define SECURITY_OPEN ( 0 )
|
|
||||||
#define SECURITY_WEP_PSK ( WEP_ENABLED )
|
|
||||||
#define SECURITY_WEP_SHARED ( WEP_ENABLED | SHARED_ENABLED )
|
|
||||||
#define SECURITY_WPA_TKIP_PSK ( WPA_SECURITY | TKIP_ENABLED )
|
|
||||||
#define SECURITY_WPA_AES_PSK ( WPA_SECURITY | AES_ENABLED )
|
|
||||||
#define SECURITY_WPA2_AES_PSK ( WPA2_SECURITY | AES_ENABLED )
|
|
||||||
#define SECURITY_WPA2_TKIP_PSK ( WPA2_SECURITY | TKIP_ENABLED )
|
|
||||||
#define SECURITY_WPA2_MIXED_PSK ( WPA2_SECURITY | AES_ENABLED | TKIP_ENABLED )
|
|
||||||
#define SECURITY_WPA_WPA2_MIXED ( WPA_SECURITY | WPA2_SECURITY )
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* WL_DEFINITIONS_H_ */
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
/*
|
|
||||||
wl_types.h - Library for Arduino Wifi shield.
|
|
||||||
Copyright (c) 2011-2014 Arduino. All right reserved.
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
* wl_types.h
|
|
||||||
*
|
|
||||||
* Created on: Jul 30, 2010
|
|
||||||
* Author: dlafauci
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef _WL_TYPES_H_
|
|
||||||
#define _WL_TYPES_H_
|
|
||||||
|
|
||||||
#include <inttypes.h>
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
WL_FAILURE = -1,
|
|
||||||
WL_SUCCESS = 1,
|
|
||||||
} wl_error_code_t;
|
|
||||||
|
|
||||||
/* Authentication modes */
|
|
||||||
enum wl_auth_mode {
|
|
||||||
AUTH_MODE_INVALID,
|
|
||||||
AUTH_MODE_AUTO,
|
|
||||||
AUTH_MODE_OPEN_SYSTEM,
|
|
||||||
AUTH_MODE_SHARED_KEY,
|
|
||||||
AUTH_MODE_WPA,
|
|
||||||
AUTH_MODE_WPA2,
|
|
||||||
AUTH_MODE_WPA_PSK,
|
|
||||||
AUTH_MODE_WPA2_PSK
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif //_WL_TYPES_H_
|
|
||||||
@@ -1,108 +0,0 @@
|
|||||||
#ifndef WSCLIENT_H
|
|
||||||
#define WSCLIENT_H
|
|
||||||
#include <websocket/libwsclient.h>
|
|
||||||
|
|
||||||
|
|
||||||
/******Define the maximum bytes of data send and receive********/
|
|
||||||
#define MAX_DATA_LEN 1500
|
|
||||||
/****************Define if using the polarssl*******************/
|
|
||||||
#define USING_SSL
|
|
||||||
|
|
||||||
|
|
||||||
/******************Define the function used*********************/
|
|
||||||
#ifdef USING_SSL
|
|
||||||
int wss_set_fun_ops(wsclient_context *wsclient);
|
|
||||||
#define wsclient_set_fun_ops(wsclient) wss_set_fun_ops(wsclient)
|
|
||||||
#else
|
|
||||||
int ws_set_fun_ops(wsclient_context *wsclient);
|
|
||||||
#define wsclient_set_fun_ops(wsclient) ws_set_fun_ops(wsclient)
|
|
||||||
#endif
|
|
||||||
/***************************************************************/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*************************************************************************************************
|
|
||||||
** Function Name : create_wsclient
|
|
||||||
** Description : Creating the websocket client context structure
|
|
||||||
** Input : url:websocket server's url
|
|
||||||
** port:websocket server's port, if not given, default 80 for "ws", 443 for "wss"
|
|
||||||
** origin: the address or url of your self
|
|
||||||
** Return : Created: websocket client context structure
|
|
||||||
** Failed: NULL
|
|
||||||
**************************************************************************************************/
|
|
||||||
wsclient_context *create_wsclient(char *url, int port,char *path, char* origin);
|
|
||||||
|
|
||||||
/*************************************************************************************************
|
|
||||||
** Function Name : ws_connect_url
|
|
||||||
** Description : Connecting to the websocket server
|
|
||||||
** Input : wsclient: the websocket client context created by create_wsclientfunction
|
|
||||||
** Return : Connected: the socket value
|
|
||||||
** Failed: -1
|
|
||||||
**************************************************************************************************/
|
|
||||||
int ws_connect_url(wsclient_context *wsclient);
|
|
||||||
|
|
||||||
/*************************************************************************************************
|
|
||||||
** Function Name : ws_send
|
|
||||||
** Description : Create the sending string data and copy to tx_buf
|
|
||||||
** Input : message: the string that send to server(cannot exceeding the MAX_DATA_LEN
|
|
||||||
** message_len: the length of the string
|
|
||||||
** use_mask: 0/1; 1 means using mask for bynary
|
|
||||||
** wsclient: the websocket client context
|
|
||||||
** Return : None
|
|
||||||
**************************************************************************************************/
|
|
||||||
void ws_send(char* message, int message_len, int use_mask, wsclient_context *wsclient);
|
|
||||||
|
|
||||||
/*************************************************************************************************
|
|
||||||
** Function Name : ws_sendBinary
|
|
||||||
** Description : Create the sending binary data and copy to tx_buf
|
|
||||||
** Input : message: the binary that send to server(cannot exceeding the MAX_DATA_LEN
|
|
||||||
** message_len: the length of the binary
|
|
||||||
** use_mask: 0/1; 1 means using mask for bynary
|
|
||||||
** wsclient: the websocket client context
|
|
||||||
** Return : None
|
|
||||||
**************************************************************************************************/
|
|
||||||
void ws_sendBinary(uint8_t* message, int message_len, int use_mask, wsclient_context *wsclient);
|
|
||||||
|
|
||||||
/*************************************************************************************************
|
|
||||||
** Function Name : ws_sendPing
|
|
||||||
** Description : Sending Ping to websocket server
|
|
||||||
** Input : wsclient: the websocket client context
|
|
||||||
** Return : None
|
|
||||||
**************************************************************************************************/
|
|
||||||
void ws_sendPing(wsclient_context *wsclient);
|
|
||||||
|
|
||||||
/*************************************************************************************************
|
|
||||||
** Function Name : ws_poll
|
|
||||||
** Description : Receicing data from server and send the data in tx_buf
|
|
||||||
** Input : timeout(in milliseconds)
|
|
||||||
wsclient: the websocket client context
|
|
||||||
** Return : None
|
|
||||||
**************************************************************************************************/
|
|
||||||
void ws_poll(int timeout, wsclient_context *wsclient);
|
|
||||||
|
|
||||||
/*************************************************************************************************
|
|
||||||
** Function Name : ws_dispatch
|
|
||||||
** Description : callback function when getting message from server
|
|
||||||
** Input : function that resolve the message received and the message length
|
|
||||||
** Return : None
|
|
||||||
**************************************************************************************************/
|
|
||||||
void ws_dispatch(void (*callback)(wsclient_context *, int)) ;
|
|
||||||
|
|
||||||
/*************************************************************************************************
|
|
||||||
** Function Name : ws_getReadyState
|
|
||||||
** Description : Getting the connection status
|
|
||||||
** Input : wsclient: the websocket client context
|
|
||||||
** Return : readyStateValues(4 types:CLOSING, CLOSED, CONNECTING, OPEN)
|
|
||||||
**************************************************************************************************/
|
|
||||||
readyStateValues ws_getReadyState(wsclient_context *wsclient);
|
|
||||||
|
|
||||||
/*************************************************************************************************
|
|
||||||
** Function Name : ws_close
|
|
||||||
** Description : Closing the connection with websocket server
|
|
||||||
** Input : wsclient: the websocket client context
|
|
||||||
** Return : None
|
|
||||||
**************************************************************************************************/
|
|
||||||
void ws_close(wsclient_context *wsclient);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
/* Copyright (c) Kuba Szczodrzyński 2022-04-24. */
|
||||||
|
|
||||||
#include "Flash.h"
|
#include "Flash.h"
|
||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
/* Copyright (c) Kuba Szczodrzyński 2022-04-24. */
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "api/Flash.h"
|
#include "api/Flash.h"
|
||||||
|
|||||||
@@ -1,16 +1,15 @@
|
|||||||
#include "PowerManagement.h"
|
#include "PowerManagement.h"
|
||||||
#include "Arduino.h"
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include "freertos_pmu.h"
|
#include <freertos_pmu.h>
|
||||||
#include "sys_api.h"
|
#include <sleep_ex_api.h>
|
||||||
#include "sleep_ex_api.h"
|
#include <sys_api.h>
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "variant.h"
|
|
||||||
|
|
||||||
#if defined(BOARD_RTL8195A)
|
#if defined(BOARD_RTL8195A)
|
||||||
#define SAVE_LOCK_PIN 18
|
#define SAVE_LOCK_PIN 18
|
||||||
#elif defined(BOARD_RTL8710)
|
#elif defined(BOARD_RTL8710)
|
||||||
@@ -22,38 +21,38 @@ extern "C" {
|
|||||||
bool PowerManagementClass::reservePLL = true;
|
bool PowerManagementClass::reservePLL = true;
|
||||||
|
|
||||||
void PowerManagementClass::sleep(uint32_t bitflg) {
|
void PowerManagementClass::sleep(uint32_t bitflg) {
|
||||||
if (!safeLock()) {
|
if (!safeLock()) {
|
||||||
pmu_release_wakelock(bitflg);
|
pmu_release_wakelock(bitflg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PowerManagementClass::sleep(void) {
|
void PowerManagementClass::sleep(void) {
|
||||||
if (!safeLock()) {
|
if (!safeLock()) {
|
||||||
pmu_release_wakelock(BIT(PMU_OS));
|
pmu_release_wakelock(BIT(PMU_OS));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PowerManagementClass::active(uint32_t bitflg) {
|
void PowerManagementClass::active(uint32_t bitflg) {
|
||||||
pmu_acquire_wakelock(bitflg);
|
pmu_acquire_wakelock(bitflg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PowerManagementClass::active(void) {
|
void PowerManagementClass::active(void) {
|
||||||
pmu_acquire_wakelock(BIT(PMU_OS));
|
pmu_acquire_wakelock(BIT(PMU_OS));
|
||||||
}
|
}
|
||||||
|
|
||||||
void PowerManagementClass::deepsleep(uint32_t duration_ms) {
|
void PowerManagementClass::deepsleep(uint32_t duration_ms) {
|
||||||
if (!safeLock()) {
|
if (!safeLock()) {
|
||||||
deepsleep_ex(DSLEEP_WAKEUP_BY_TIMER, duration_ms);
|
deepsleep_ex(DSLEEP_WAKEUP_BY_TIMER, duration_ms);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PowerManagementClass::safeLock() {
|
bool PowerManagementClass::safeLock() {
|
||||||
pinMode(SAVE_LOCK_PIN, INPUT_PULLUP);
|
pinMode(SAVE_LOCK_PIN, INPUT_PULLUP);
|
||||||
return (digitalRead(SAVE_LOCK_PIN) == 1) ? false : true;
|
return (digitalRead(SAVE_LOCK_PIN) == 1) ? false : true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PowerManagementClass::softReset() {
|
void PowerManagementClass::softReset() {
|
||||||
sys_reset();
|
sys_reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
PowerManagementClass PowerManagement;
|
PowerManagementClass PowerManagement;
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class PowerManagementClass PowerManagement.h
|
||||||
|
* @brief Power management in Ameba
|
||||||
|
*/
|
||||||
|
class PowerManagementClass {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Allow OS automatically save power while idle
|
||||||
|
*
|
||||||
|
* As OS consider it would idle for more than 2s, it will invoke system suspend.
|
||||||
|
* If wlan is associated with AP, than it will under asslociated idle state.
|
||||||
|
*/
|
||||||
|
static void sleep(void);
|
||||||
|
static void sleep(uint32_t bitflg);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Disallow OS automatically save power while idle
|
||||||
|
*/
|
||||||
|
static void active(void);
|
||||||
|
static void active(uint32_t bitflg);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Reserved PLL while sleep
|
||||||
|
*
|
||||||
|
* Reserve PLL would keep FIFO of peripherals (Ex. UART) but cost more power (around 5mA).
|
||||||
|
* If we don't reserve PLL, it saves more power but we might missing data because FIFO is turned of this way.
|
||||||
|
*
|
||||||
|
* @param[in] reserve true for reserved, false for non-reserved
|
||||||
|
*/
|
||||||
|
static void setPllReserved(bool reserve);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enter deepsleep immediately
|
||||||
|
*
|
||||||
|
* Invoke deepsleep would make system enter deepsleep state immediately.
|
||||||
|
* It's the state that saves most power.
|
||||||
|
* As it wakeup from deepsleep, the system would behave just like reboot.
|
||||||
|
*
|
||||||
|
* @param[in] duration_ms wakeup after specific time in unit of millisecond
|
||||||
|
*/
|
||||||
|
static void deepsleep(uint32_t duration_ms);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Check if system is allowed enter any power save state
|
||||||
|
*
|
||||||
|
* The pin 18 (GPIOE_5) is designed as safe lock.
|
||||||
|
* If pin 18 is HIGH, then we prevent Ameba enter any power save state.\n\n
|
||||||
|
* Under any power save state, we are not able to flash image to Ameba.
|
||||||
|
* Thus if user misuse deepsleep and make Ameba enter deepsleep immediately after boot up,
|
||||||
|
* then he would find it's hard to flash image.
|
||||||
|
* In this case, he can pull up pin 18.
|
||||||
|
*
|
||||||
|
* @return true if system not allowed enter any power save state, and false vise versa
|
||||||
|
*/
|
||||||
|
static bool safeLock();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Reboot system
|
||||||
|
*
|
||||||
|
* Reboot system in soft way. Some registers is not powered off in this case, but mostly we could regard this as
|
||||||
|
* reboot.
|
||||||
|
*/
|
||||||
|
static void softReset();
|
||||||
|
|
||||||
|
private:
|
||||||
|
static bool reservePLL;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern PowerManagementClass PowerManagement;
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
/* Copyright (c) Kuba Szczodrzyński 2022-04-25. */
|
||||||
|
|
||||||
#include "WiFi.h"
|
#include "WiFi.h"
|
||||||
#include "WiFiPriv.h"
|
#include "WiFiPriv.h"
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
/* Copyright (c) Kuba Szczodrzyński 2022-04-25. */
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
/* Copyright (c) Kuba Szczodrzyński 2022-04-25. */
|
||||||
|
|
||||||
#include "WiFi.h"
|
#include "WiFi.h"
|
||||||
#include "WiFiPriv.h"
|
#include "WiFiPriv.h"
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
/* Copyright (c) Kuba Szczodrzyński 2022-04-26. */
|
||||||
|
|
||||||
#include "WiFiClient.h"
|
#include "WiFiClient.h"
|
||||||
#include "WiFiPriv.h"
|
#include "WiFiPriv.h"
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
|
/* Copyright (c) Kuba Szczodrzyński 2022-04-26. */
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <api/WiFiClient.h>
|
|
||||||
#include <LwIPRxBuffer.h>
|
#include <LwIPRxBuffer.h>
|
||||||
|
#include <api/WiFiClient.h>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
class SocketHandle;
|
class SocketHandle;
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
/* Copyright (c) Kuba Szczodrzyński 2022-04-25. */
|
||||||
|
|
||||||
#include "WiFi.h"
|
#include "WiFi.h"
|
||||||
#include "WiFiPriv.h"
|
#include "WiFiPriv.h"
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
/* Copyright (c) Kuba Szczodrzyński 2022-04-25. */
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
/* Copyright (c) Kuba Szczodrzyński 2022-04-25. */
|
||||||
|
|
||||||
#include "WiFi.h"
|
#include "WiFi.h"
|
||||||
#include "WiFiPriv.h"
|
#include "WiFiPriv.h"
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
/* Copyright (c) Kuba Szczodrzyński 2022-04-25. */
|
||||||
|
|
||||||
#include "WiFi.h"
|
#include "WiFi.h"
|
||||||
#include "WiFiPriv.h"
|
#include "WiFiPriv.h"
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
/* Copyright (c) Kuba Szczodrzyński 2022-04-26. */
|
||||||
|
|
||||||
#include "WiFiServer.h"
|
#include "WiFiServer.h"
|
||||||
#include "WiFiPriv.h"
|
#include "WiFiPriv.h"
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
/* Copyright (c) Kuba Szczodrzyński 2022-04-26. */
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <api/WiFiServer.h>
|
#include <api/WiFiServer.h>
|
||||||
|
|||||||
@@ -1,20 +1 @@
|
|||||||
/*
|
|
||||||
Copyright (c) 2011 Arduino. All right reserved.
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
See the GNU Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
// API compatibility
|
|
||||||
#include "variant.h"
|
#include "variant.h"
|
||||||
|
|||||||
@@ -1,33 +1,13 @@
|
|||||||
/*
|
/* Copyright (c) Kuba Szczodrzyński 2022-04-22. */
|
||||||
Copyright (c) 2011 Arduino. All right reserved.
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
See the GNU Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
#include "Arduino.h"
|
|
||||||
#include "variant.h"
|
#include "variant.h"
|
||||||
#include "gpio_api.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "PinNames.h"
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Pins descriptions
|
* Pins descriptions
|
||||||
*/
|
*/
|
||||||
|
// clang-format off
|
||||||
PinDescription g_APinDescription[PINS_COUNT] = {
|
PinDescription g_APinDescription[PINS_COUNT] = {
|
||||||
// D0: UART0_RTS, SPI1_MISO, SPI0_MISO, I2C0_SCL, SD_D0, PWM5, I2S_WS, WAKEUP_2
|
// D0: UART0_RTS, SPI1_MISO, SPI0_MISO, I2C0_SCL, SD_D0, PWM5, I2S_WS, WAKEUP_2
|
||||||
{PA_22, NOT_INITIAL, PIO_GPIO | PIO_GPIO_IRQ | PIO_PWM, NOT_INITIAL},
|
{PA_22, NOT_INITIAL, PIO_GPIO | PIO_GPIO_IRQ | PIO_PWM, NOT_INITIAL},
|
||||||
@@ -48,31 +28,15 @@ PinDescription g_APinDescription[PINS_COUNT] = {
|
|||||||
// D8: SDIO_SIDEBAND_INT, PWM4, WAKEUP_1
|
// D8: SDIO_SIDEBAND_INT, PWM4, WAKEUP_1
|
||||||
{PA_5, NOT_INITIAL, PIO_GPIO | PIO_GPIO_IRQ | PIO_PWM, NOT_INITIAL},
|
{PA_5, NOT_INITIAL, PIO_GPIO | PIO_GPIO_IRQ | PIO_PWM, NOT_INITIAL},
|
||||||
// D9: PWM3
|
// D9: PWM3
|
||||||
{PA_12, NOT_INITIAL, PIO_GPIO | PIO_GPIO_IRQ | PIO_PWM, NOT_INITIAL},
|
{PA_12, NOT_INITIAL, PIO_GPIO | PIO_GPIO_IRQ | PIO_PWM, NOT_INITIAL},
|
||||||
// D10: UART0_RXD, SPI1_CLK, SPI0_SCK, I2C1_SCL, SD_D2, TIMER4_TRIG, I2S_MCK, WAKEUP_0
|
// D10: UART0_RXD, SPI1_CLK, SPI0_SCK, I2C1_SCL, SD_D2, TIMER4_TRIG, I2S_MCK, WAKEUP_0
|
||||||
{PA_18, NOT_INITIAL, PIO_GPIO | PIO_GPIO_IRQ, NOT_INITIAL},
|
{PA_18, NOT_INITIAL, PIO_GPIO | PIO_GPIO_IRQ, NOT_INITIAL},
|
||||||
// D11: UART0_TXD, SPI1_MOSI, SPI0_MOSI, I2C1_SDA, SD_D1, PWM0, WAKEUP_3
|
// D11: UART0_TXD, SPI1_MOSI, SPI0_MOSI, I2C1_SDA, SD_D1, PWM0, WAKEUP_3
|
||||||
{PA_23, NOT_INITIAL, PIO_GPIO | PIO_GPIO_IRQ | PIO_PWM, NOT_INITIAL},
|
{PA_23, NOT_INITIAL, PIO_GPIO | PIO_GPIO_IRQ | PIO_PWM, NOT_INITIAL},
|
||||||
};
|
};
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
void *gpio_pin_struct[PINS_COUNT] = {NULL};
|
void *gpio_pin_struct[PINS_COUNT] = {NULL};
|
||||||
void *gpio_irq_handler_list[PINS_COUNT] = {NULL};
|
void *gpio_irq_handler_list[PINS_COUNT] = {NULL};
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
} // extern C
|
} // extern C
|
||||||
#endif
|
|
||||||
|
|
||||||
void serialEvent() __attribute__((weak));
|
|
||||||
bool Serial_available() __attribute__((weak));
|
|
||||||
|
|
||||||
void serialEventRun(void) {
|
|
||||||
if (Serial_available && serialEvent && Serial_available())
|
|
||||||
serialEvent();
|
|
||||||
}
|
|
||||||
|
|
||||||
void wait_for_debug() {
|
|
||||||
while (((CoreDebug->DHCSR) & CoreDebug_DHCSR_C_DEBUGEN_Msk) == 0) {
|
|
||||||
asm("nop");
|
|
||||||
}
|
|
||||||
delay(1000);
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,20 +1,4 @@
|
|||||||
/*
|
/* Copyright (c) Kuba Szczodrzyński 2022-04-23. */
|
||||||
Copyright (c) 2011 Arduino. All right reserved.
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
See the GNU Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
@@ -24,10 +8,10 @@
|
|||||||
// ----
|
// ----
|
||||||
|
|
||||||
// Number of pins defined in PinDescription array
|
// Number of pins defined in PinDescription array
|
||||||
#define PINS_COUNT (12u)
|
#define PINS_COUNT (12u)
|
||||||
#define NUM_DIGITAL_PINS (12u)
|
#define NUM_DIGITAL_PINS (12u)
|
||||||
#define NUM_ANALOG_INPUTS (2u)
|
#define NUM_ANALOG_INPUTS (2u)
|
||||||
#define NUM_ANALOG_OUTPUTS (0u)
|
#define NUM_ANALOG_OUTPUTS (0u)
|
||||||
|
|
||||||
// Low-level pin register query macros
|
// Low-level pin register query macros
|
||||||
// -----------------------------------
|
// -----------------------------------
|
||||||
@@ -37,18 +21,18 @@
|
|||||||
|
|
||||||
// LEDs
|
// LEDs
|
||||||
// ----
|
// ----
|
||||||
#define PIN_LED (4u)
|
#define PIN_LED (4u)
|
||||||
#define LED_BUILTIN PIN_LED
|
#define LED_BUILTIN PIN_LED
|
||||||
|
|
||||||
// Analog pins
|
// Analog pins
|
||||||
// -----------
|
// -----------
|
||||||
#define PIN_A0 (1u) // PA_19
|
#define PIN_A0 (1u) // PA_19
|
||||||
#define PIN_A1 (0u) // dummy, this is NOT usable
|
#define PIN_A1 (0u) // dummy, this is NOT usable
|
||||||
#define PIN_A2 (5u) // PA_20
|
#define PIN_A2 (5u) // PA_20
|
||||||
|
|
||||||
static const uint8_t A0 = PIN_A0;
|
static const uint8_t A0 = PIN_A0;
|
||||||
static const uint8_t A1 = PIN_A1;
|
static const uint8_t A1 = PIN_A1;
|
||||||
static const uint8_t A2 = PIN_A2;
|
static const uint8_t A2 = PIN_A2;
|
||||||
|
|
||||||
// SPI Interfaces
|
// SPI Interfaces
|
||||||
// --------------
|
// --------------
|
||||||
@@ -64,30 +48,14 @@ static const uint8_t A2 = PIN_A2;
|
|||||||
#include "LOGUARTClass.h"
|
#include "LOGUARTClass.h"
|
||||||
extern LOGUARTClass Serial;
|
extern LOGUARTClass Serial;
|
||||||
// LOGUARTClass
|
// LOGUARTClass
|
||||||
#define PIN_SERIAL2_RX PA_29
|
#define PIN_SERIAL2_RX PA_29
|
||||||
#define PIN_SERIAL2_TX PA_30
|
#define PIN_SERIAL2_TX PA_30
|
||||||
// UARTClassOne
|
// UARTClassOne
|
||||||
#define PIN_SERIAL0_RX PA_18
|
#define PIN_SERIAL0_RX PA_18
|
||||||
#define PIN_SERIAL0_TX PA_23
|
#define PIN_SERIAL0_TX PA_23
|
||||||
#endif // __cplusplus
|
#endif // __cplusplus
|
||||||
|
|
||||||
#define SERIAL_PORT_USBVIRTUAL Serial
|
#define SERIAL_PORT_USBVIRTUAL Serial
|
||||||
#define SERIAL_PORT_MONITOR Serial
|
#define SERIAL_PORT_MONITOR Serial
|
||||||
#define SERIAL_PORT_HARDWARE Serial
|
#define SERIAL_PORT_HARDWARE Serial
|
||||||
#define SERIAL_PORT_HARDWARE_OPEN Serial
|
#define SERIAL_PORT_HARDWARE_OPEN Serial
|
||||||
|
|
||||||
// Misc
|
|
||||||
// ----
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif // __cplusplus
|
|
||||||
/*
|
|
||||||
* Wait until enter debug mode
|
|
||||||
*
|
|
||||||
* Check DHCSR(0xE000EDF0) register and hold until bit C_DEBUGEN is set.
|
|
||||||
* Use this function along with J-LINK or other debug tool
|
|
||||||
**/
|
|
||||||
extern void wait_for_debug();
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ env.AddLibrary(
|
|||||||
base_dir=LT_API_DIR,
|
base_dir=LT_API_DIR,
|
||||||
srcs=[
|
srcs=[
|
||||||
"+<api/*.c*>",
|
"+<api/*.c*>",
|
||||||
|
"+<common/*.c*>",
|
||||||
"+<libraries/**/*.c*>",
|
"+<libraries/**/*.c*>",
|
||||||
],
|
],
|
||||||
includes=[
|
includes=[
|
||||||
|
|||||||
@@ -70,38 +70,12 @@ env.AddLibrary(
|
|||||||
base_dir="$ARDUINO_DIR",
|
base_dir="$ARDUINO_DIR",
|
||||||
srcs=[
|
srcs=[
|
||||||
# Wiring core
|
# Wiring core
|
||||||
"+<cores/arduino/avr/dtostrf.c>",
|
"+<cores/arduino/*.c>",
|
||||||
"+<cores/arduino/b64.cpp>",
|
"+<cores/arduino/*.cpp>",
|
||||||
"+<cores/arduino/cxxabi-compat.cpp>",
|
|
||||||
"+<cores/arduino/hooks.c>",
|
|
||||||
"+<cores/arduino/itoa.c>",
|
|
||||||
"+<cores/arduino/LOGUARTClass.cpp>",
|
|
||||||
"+<cores/arduino/lwip_info.c>",
|
|
||||||
"+<cores/arduino/main.cpp>",
|
|
||||||
"+<cores/arduino/PowerManagement.cpp>",
|
|
||||||
"+<cores/arduino/rtl_sys.cpp>",
|
|
||||||
"+<cores/arduino/spiffs/spiffs_cache.c>",
|
|
||||||
"+<cores/arduino/spiffs/spiffs_check.c>",
|
|
||||||
"+<cores/arduino/spiffs/spiffs_gc.c>",
|
|
||||||
"+<cores/arduino/spiffs/spiffs_hydrogen.c>",
|
|
||||||
"+<cores/arduino/spiffs/spiffs_nucleus.c>",
|
|
||||||
"+<cores/arduino/Tone.cpp>",
|
|
||||||
"+<cores/arduino/WebSocketClient.cpp>",
|
|
||||||
"+<cores/arduino/WInterrupts.c>",
|
|
||||||
"+<cores/arduino/wiring.c>",
|
|
||||||
"+<cores/arduino/wiring_analog.c>",
|
|
||||||
"+<cores/arduino/wiring_digital.c>",
|
|
||||||
"+<cores/arduino/wiring_os.c>",
|
|
||||||
"+<cores/arduino/wiring_pulse.cpp>",
|
|
||||||
"+<cores/arduino/wiring_shift.c>",
|
|
||||||
"+<cores/arduino/wiring_watchdog.c>",
|
|
||||||
"+<cores/arduino/WMath.cpp>",
|
|
||||||
],
|
],
|
||||||
includes=[
|
includes=[
|
||||||
# prepend these as the Arduino core is incorrectly picking some includes from SDK
|
# prepend these as the Arduino core is incorrectly picking some includes from SDK
|
||||||
"!<cores/arduino>",
|
"!<cores/arduino>",
|
||||||
"!<cores/arduino/avr>",
|
|
||||||
"!<cores/arduino/spiffs>",
|
|
||||||
# includes that are missing in the vanilla SDK makefiles
|
# includes that are missing in the vanilla SDK makefiles
|
||||||
"+<$SDK_DIR/component/common/drivers/sdio/realtek/sdio_host/inc>",
|
"+<$SDK_DIR/component/common/drivers/sdio/realtek/sdio_host/inc>",
|
||||||
"+<$SDK_DIR/component/common/file_system/fatfs>",
|
"+<$SDK_DIR/component/common/file_system/fatfs>",
|
||||||
|
|||||||
2
platform/realtek-ambz/fixups/.clang-format
Normal file
2
platform/realtek-ambz/fixups/.clang-format
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
DisableFormat: true
|
||||||
|
SortIncludes: Never
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
/* Copyright (c) Kuba Szczodrzyński 2022-04-23. */
|
||||||
|
|
||||||
/* WCharacter.h uses deprecated isascii() and toascii(),
|
/* WCharacter.h uses deprecated isascii() and toascii(),
|
||||||
which are available in gnu++11 but not c++11 */
|
which are available in gnu++11 but not c++11 */
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user