Unverified Commit 67027c0d authored by Marcel Stör's avatar Marcel Stör Committed by GitHub
Browse files

Merge pull request #2340 from nodemcu/dev

2.2 master snap
parents 5073c199 18f33f5f
...@@ -38,6 +38,11 @@ ...@@ -38,6 +38,11 @@
#if !defined(MBEDTLS_TIMING_ALT) #if !defined(MBEDTLS_TIMING_ALT)
#if !defined(unix) && !defined(__unix__) && !defined(__unix) && \
!defined(__APPLE__) && !defined(_WIN32)
#error "This module only works on Unix and Windows, see MBEDTLS_TIMING_C in config.h"
#endif
#ifndef asm #ifndef asm
#define asm __asm #define asm __asm
#endif #endif
...@@ -239,21 +244,23 @@ volatile int mbedtls_timing_alarmed = 0; ...@@ -239,21 +244,23 @@ volatile int mbedtls_timing_alarmed = 0;
unsigned long mbedtls_timing_get_timer( struct mbedtls_timing_hr_time *val, int reset ) unsigned long mbedtls_timing_get_timer( struct mbedtls_timing_hr_time *val, int reset )
{ {
unsigned long delta;
LARGE_INTEGER offset, hfreq;
struct _hr_time *t = (struct _hr_time *) val; struct _hr_time *t = (struct _hr_time *) val;
QueryPerformanceCounter( &offset );
QueryPerformanceFrequency( &hfreq );
delta = (unsigned long)( ( 1000 *
( offset.QuadPart - t->start.QuadPart ) ) /
hfreq.QuadPart );
if( reset ) if( reset )
{
QueryPerformanceCounter( &t->start ); QueryPerformanceCounter( &t->start );
return( 0 );
}
else
{
unsigned long delta;
LARGE_INTEGER now, hfreq;
QueryPerformanceCounter( &now );
QueryPerformanceFrequency( &hfreq );
delta = (unsigned long)( ( now.QuadPart - t->start.QuadPart ) * 1000ul
/ hfreq.QuadPart );
return( delta ); return( delta );
}
} }
/* It's OK to use a global because alarm() is supposed to be global anyway */ /* It's OK to use a global because alarm() is supposed to be global anyway */
...@@ -271,6 +278,14 @@ void mbedtls_set_alarm( int seconds ) ...@@ -271,6 +278,14 @@ void mbedtls_set_alarm( int seconds )
{ {
DWORD ThreadId; DWORD ThreadId;
if( seconds == 0 )
{
/* No need to create a thread for this simple case.
* Also, this shorcut is more reliable at least on MinGW32 */
mbedtls_timing_alarmed = 1;
return;
}
mbedtls_timing_alarmed = 0; mbedtls_timing_alarmed = 0;
alarmMs = seconds * 1000; alarmMs = seconds * 1000;
CloseHandle( CreateThread( NULL, 0, TimerProc, NULL, 0, &ThreadId ) ); CloseHandle( CreateThread( NULL, 0, TimerProc, NULL, 0, &ThreadId ) );
...@@ -280,23 +295,22 @@ void mbedtls_set_alarm( int seconds ) ...@@ -280,23 +295,22 @@ void mbedtls_set_alarm( int seconds )
unsigned long mbedtls_timing_get_timer( struct mbedtls_timing_hr_time *val, int reset ) unsigned long mbedtls_timing_get_timer( struct mbedtls_timing_hr_time *val, int reset )
{ {
unsigned long delta;
struct timeval offset;
struct _hr_time *t = (struct _hr_time *) val; struct _hr_time *t = (struct _hr_time *) val;
gettimeofday( &offset, NULL );
if( reset ) if( reset )
{ {
t->start.tv_sec = offset.tv_sec; gettimeofday( &t->start, NULL );
t->start.tv_usec = offset.tv_usec;
return( 0 ); return( 0 );
} }
else
delta = ( offset.tv_sec - t->start.tv_sec ) * 1000 {
+ ( offset.tv_usec - t->start.tv_usec ) / 1000; unsigned long delta;
struct timeval now;
gettimeofday( &now, NULL );
delta = ( now.tv_sec - t->start.tv_sec ) * 1000ul
+ ( now.tv_usec - t->start.tv_usec ) / 1000;
return( delta ); return( delta );
}
} }
static void sighandler( int signum ) static void sighandler( int signum )
...@@ -310,6 +324,12 @@ void mbedtls_set_alarm( int seconds ) ...@@ -310,6 +324,12 @@ void mbedtls_set_alarm( int seconds )
mbedtls_timing_alarmed = 0; mbedtls_timing_alarmed = 0;
signal( SIGALRM, sighandler ); signal( SIGALRM, sighandler );
alarm( seconds ); alarm( seconds );
if( seconds == 0 )
{
/* alarm(0) cancelled any previous pending alarm, but the
handler won't fire, so raise the flag straight away. */
mbedtls_timing_alarmed = 1;
}
} }
#endif /* _WIN32 && !EFIX64 && !EFI32 */ #endif /* _WIN32 && !EFIX64 && !EFI32 */
...@@ -374,12 +394,20 @@ static void busy_msleep( unsigned long msec ) ...@@ -374,12 +394,20 @@ static void busy_msleep( unsigned long msec )
} }
#define FAIL do \ #define FAIL do \
{ \ { \
if( verbose != 0 ) \ if( verbose != 0 ) \
mbedtls_printf( "failed\n" ); \ { \
\ mbedtls_printf( "failed at line %d\n", __LINE__ ); \
mbedtls_printf( " cycles=%lu ratio=%lu millisecs=%lu secs=%lu hardfail=%d a=%lu b=%lu\n", \
cycles, ratio, millisecs, secs, hardfail, \
(unsigned long) a, (unsigned long) b ); \
mbedtls_printf( " elapsed(hires)=%lu elapsed(ctx)=%lu status(ctx)=%d\n", \
mbedtls_timing_get_timer( &hires, 0 ), \
mbedtls_timing_get_timer( &ctx.timer, 0 ), \
mbedtls_timing_get_delay( &ctx ) ); \
} \
return( 1 ); \ return( 1 ); \
} while( 0 ) } while( 0 )
/* /*
* Checkup routine * Checkup routine
...@@ -389,22 +417,22 @@ static void busy_msleep( unsigned long msec ) ...@@ -389,22 +417,22 @@ static void busy_msleep( unsigned long msec )
*/ */
int mbedtls_timing_self_test( int verbose ) int mbedtls_timing_self_test( int verbose )
{ {
unsigned long cycles, ratio; unsigned long cycles = 0, ratio = 0;
unsigned long millisecs, secs; unsigned long millisecs = 0, secs = 0;
int hardfail; int hardfail = 0;
struct mbedtls_timing_hr_time hires; struct mbedtls_timing_hr_time hires;
uint32_t a, b; uint32_t a = 0, b = 0;
mbedtls_timing_delay_context ctx; mbedtls_timing_delay_context ctx;
if( verbose != 0 ) if( verbose != 0 )
mbedtls_printf( " TIMING tests note: will take some time!\n" ); mbedtls_printf( " TIMING tests note: will take some time!\n" );
if( verbose != 0 ) if( verbose != 0 )
mbedtls_printf( " TIMING test #1 (set_alarm / get_timer): " ); mbedtls_printf( " TIMING test #1 (set_alarm / get_timer): " );
for( secs = 1; secs <= 3; secs++ )
{ {
secs = 1;
(void) mbedtls_timing_get_timer( &hires, 1 ); (void) mbedtls_timing_get_timer( &hires, 1 );
mbedtls_set_alarm( (int) secs ); mbedtls_set_alarm( (int) secs );
...@@ -416,12 +444,7 @@ int mbedtls_timing_self_test( int verbose ) ...@@ -416,12 +444,7 @@ int mbedtls_timing_self_test( int verbose )
/* For some reason on Windows it looks like alarm has an extra delay /* For some reason on Windows it looks like alarm has an extra delay
* (maybe related to creating a new thread). Allow some room here. */ * (maybe related to creating a new thread). Allow some room here. */
if( millisecs < 800 * secs || millisecs > 1200 * secs + 300 ) if( millisecs < 800 * secs || millisecs > 1200 * secs + 300 )
{ FAIL;
if( verbose != 0 )
mbedtls_printf( "failed\n" );
return( 1 );
}
} }
if( verbose != 0 ) if( verbose != 0 )
...@@ -430,29 +453,23 @@ int mbedtls_timing_self_test( int verbose ) ...@@ -430,29 +453,23 @@ int mbedtls_timing_self_test( int verbose )
if( verbose != 0 ) if( verbose != 0 )
mbedtls_printf( " TIMING test #2 (set/get_delay ): " ); mbedtls_printf( " TIMING test #2 (set/get_delay ): " );
for( a = 200; a <= 400; a += 200 )
{ {
for( b = 200; b <= 400; b += 200 ) a = 800;
{ b = 400;
mbedtls_timing_set_delay( &ctx, a, a + b ); mbedtls_timing_set_delay( &ctx, a, a + b ); /* T = 0 */
busy_msleep( a - a / 8 ); busy_msleep( a - a / 4 ); /* T = a - a/4 */
if( mbedtls_timing_get_delay( &ctx ) != 0 ) if( mbedtls_timing_get_delay( &ctx ) != 0 )
FAIL; FAIL;
busy_msleep( a / 4 ); busy_msleep( a / 4 + b / 4 ); /* T = a + b/4 */
if( mbedtls_timing_get_delay( &ctx ) != 1 ) if( mbedtls_timing_get_delay( &ctx ) != 1 )
FAIL; FAIL;
busy_msleep( b - a / 8 - b / 8 ); busy_msleep( b ); /* T = a + b + b/4 */
if( mbedtls_timing_get_delay( &ctx ) != 1 )
FAIL;
busy_msleep( b / 4 );
if( mbedtls_timing_get_delay( &ctx ) != 2 ) if( mbedtls_timing_get_delay( &ctx ) != 2 )
FAIL; FAIL;
} }
}
mbedtls_timing_set_delay( &ctx, 0, 0 ); mbedtls_timing_set_delay( &ctx, 0, 0 );
busy_msleep( 200 ); busy_msleep( 200 );
...@@ -470,7 +487,6 @@ int mbedtls_timing_self_test( int verbose ) ...@@ -470,7 +487,6 @@ int mbedtls_timing_self_test( int verbose )
* On a 4Ghz 32-bit machine the cycle counter wraps about once per second; * On a 4Ghz 32-bit machine the cycle counter wraps about once per second;
* since the whole test is about 10ms, it shouldn't happen twice in a row. * since the whole test is about 10ms, it shouldn't happen twice in a row.
*/ */
hardfail = 0;
hard_test: hard_test:
if( hardfail > 1 ) if( hardfail > 1 )
......
...@@ -36,6 +36,9 @@ static const char *features[] = { ...@@ -36,6 +36,9 @@ static const char *features[] = {
#if defined(MBEDTLS_HAVE_ASM) #if defined(MBEDTLS_HAVE_ASM)
"MBEDTLS_HAVE_ASM", "MBEDTLS_HAVE_ASM",
#endif /* MBEDTLS_HAVE_ASM */ #endif /* MBEDTLS_HAVE_ASM */
#if defined(MBEDTLS_NO_UDBL_DIVISION)
"MBEDTLS_NO_UDBL_DIVISION",
#endif /* MBEDTLS_NO_UDBL_DIVISION */
#if defined(MBEDTLS_HAVE_SSE2) #if defined(MBEDTLS_HAVE_SSE2)
"MBEDTLS_HAVE_SSE2", "MBEDTLS_HAVE_SSE2",
#endif /* MBEDTLS_HAVE_SSE2 */ #endif /* MBEDTLS_HAVE_SSE2 */
...@@ -54,6 +57,9 @@ static const char *features[] = { ...@@ -54,6 +57,9 @@ static const char *features[] = {
#if defined(MBEDTLS_PLATFORM_EXIT_ALT) #if defined(MBEDTLS_PLATFORM_EXIT_ALT)
"MBEDTLS_PLATFORM_EXIT_ALT", "MBEDTLS_PLATFORM_EXIT_ALT",
#endif /* MBEDTLS_PLATFORM_EXIT_ALT */ #endif /* MBEDTLS_PLATFORM_EXIT_ALT */
#if defined(MBEDTLS_PLATFORM_TIME_ALT)
"MBEDTLS_PLATFORM_TIME_ALT",
#endif /* MBEDTLS_PLATFORM_TIME_ALT */
#if defined(MBEDTLS_PLATFORM_FPRINTF_ALT) #if defined(MBEDTLS_PLATFORM_FPRINTF_ALT)
"MBEDTLS_PLATFORM_FPRINTF_ALT", "MBEDTLS_PLATFORM_FPRINTF_ALT",
#endif /* MBEDTLS_PLATFORM_FPRINTF_ALT */ #endif /* MBEDTLS_PLATFORM_FPRINTF_ALT */
...@@ -63,6 +69,12 @@ static const char *features[] = { ...@@ -63,6 +69,12 @@ static const char *features[] = {
#if defined(MBEDTLS_PLATFORM_SNPRINTF_ALT) #if defined(MBEDTLS_PLATFORM_SNPRINTF_ALT)
"MBEDTLS_PLATFORM_SNPRINTF_ALT", "MBEDTLS_PLATFORM_SNPRINTF_ALT",
#endif /* MBEDTLS_PLATFORM_SNPRINTF_ALT */ #endif /* MBEDTLS_PLATFORM_SNPRINTF_ALT */
#if defined(MBEDTLS_PLATFORM_NV_SEED_ALT)
"MBEDTLS_PLATFORM_NV_SEED_ALT",
#endif /* MBEDTLS_PLATFORM_NV_SEED_ALT */
#if defined(MBEDTLS_PLATFORM_SETUP_TEARDOWN_ALT)
"MBEDTLS_PLATFORM_SETUP_TEARDOWN_ALT",
#endif /* MBEDTLS_PLATFORM_SETUP_TEARDOWN_ALT */
#if defined(MBEDTLS_DEPRECATED_WARNING) #if defined(MBEDTLS_DEPRECATED_WARNING)
"MBEDTLS_DEPRECATED_WARNING", "MBEDTLS_DEPRECATED_WARNING",
#endif /* MBEDTLS_DEPRECATED_WARNING */ #endif /* MBEDTLS_DEPRECATED_WARNING */
...@@ -84,12 +96,24 @@ static const char *features[] = { ...@@ -84,12 +96,24 @@ static const char *features[] = {
#if defined(MBEDTLS_CAMELLIA_ALT) #if defined(MBEDTLS_CAMELLIA_ALT)
"MBEDTLS_CAMELLIA_ALT", "MBEDTLS_CAMELLIA_ALT",
#endif /* MBEDTLS_CAMELLIA_ALT */ #endif /* MBEDTLS_CAMELLIA_ALT */
#if defined(MBEDTLS_CCM_ALT)
"MBEDTLS_CCM_ALT",
#endif /* MBEDTLS_CCM_ALT */
#if defined(MBEDTLS_CMAC_ALT)
"MBEDTLS_CMAC_ALT",
#endif /* MBEDTLS_CMAC_ALT */
#if defined(MBEDTLS_DES_ALT) #if defined(MBEDTLS_DES_ALT)
"MBEDTLS_DES_ALT", "MBEDTLS_DES_ALT",
#endif /* MBEDTLS_DES_ALT */ #endif /* MBEDTLS_DES_ALT */
#if defined(MBEDTLS_XTEA_ALT) #if defined(MBEDTLS_DHM_ALT)
"MBEDTLS_XTEA_ALT", "MBEDTLS_DHM_ALT",
#endif /* MBEDTLS_XTEA_ALT */ #endif /* MBEDTLS_DHM_ALT */
#if defined(MBEDTLS_ECJPAKE_ALT)
"MBEDTLS_ECJPAKE_ALT",
#endif /* MBEDTLS_ECJPAKE_ALT */
#if defined(MBEDTLS_GCM_ALT)
"MBEDTLS_GCM_ALT",
#endif /* MBEDTLS_GCM_ALT */
#if defined(MBEDTLS_MD2_ALT) #if defined(MBEDTLS_MD2_ALT)
"MBEDTLS_MD2_ALT", "MBEDTLS_MD2_ALT",
#endif /* MBEDTLS_MD2_ALT */ #endif /* MBEDTLS_MD2_ALT */
...@@ -102,6 +126,9 @@ static const char *features[] = { ...@@ -102,6 +126,9 @@ static const char *features[] = {
#if defined(MBEDTLS_RIPEMD160_ALT) #if defined(MBEDTLS_RIPEMD160_ALT)
"MBEDTLS_RIPEMD160_ALT", "MBEDTLS_RIPEMD160_ALT",
#endif /* MBEDTLS_RIPEMD160_ALT */ #endif /* MBEDTLS_RIPEMD160_ALT */
#if defined(MBEDTLS_RSA_ALT)
"MBEDTLS_RSA_ALT",
#endif /* MBEDTLS_RSA_ALT */
#if defined(MBEDTLS_SHA1_ALT) #if defined(MBEDTLS_SHA1_ALT)
"MBEDTLS_SHA1_ALT", "MBEDTLS_SHA1_ALT",
#endif /* MBEDTLS_SHA1_ALT */ #endif /* MBEDTLS_SHA1_ALT */
...@@ -111,6 +138,12 @@ static const char *features[] = { ...@@ -111,6 +138,12 @@ static const char *features[] = {
#if defined(MBEDTLS_SHA512_ALT) #if defined(MBEDTLS_SHA512_ALT)
"MBEDTLS_SHA512_ALT", "MBEDTLS_SHA512_ALT",
#endif /* MBEDTLS_SHA512_ALT */ #endif /* MBEDTLS_SHA512_ALT */
#if defined(MBEDTLS_XTEA_ALT)
"MBEDTLS_XTEA_ALT",
#endif /* MBEDTLS_XTEA_ALT */
#if defined(MBEDTLS_ECP_ALT)
"MBEDTLS_ECP_ALT",
#endif /* MBEDTLS_ECP_ALT */
#if defined(MBEDTLS_MD2_PROCESS_ALT) #if defined(MBEDTLS_MD2_PROCESS_ALT)
"MBEDTLS_MD2_PROCESS_ALT", "MBEDTLS_MD2_PROCESS_ALT",
#endif /* MBEDTLS_MD2_PROCESS_ALT */ #endif /* MBEDTLS_MD2_PROCESS_ALT */
...@@ -153,6 +186,51 @@ static const char *features[] = { ...@@ -153,6 +186,51 @@ static const char *features[] = {
#if defined(MBEDTLS_AES_DECRYPT_ALT) #if defined(MBEDTLS_AES_DECRYPT_ALT)
"MBEDTLS_AES_DECRYPT_ALT", "MBEDTLS_AES_DECRYPT_ALT",
#endif /* MBEDTLS_AES_DECRYPT_ALT */ #endif /* MBEDTLS_AES_DECRYPT_ALT */
#if defined(MBEDTLS_ECDH_GEN_PUBLIC_ALT)
"MBEDTLS_ECDH_GEN_PUBLIC_ALT",
#endif /* MBEDTLS_ECDH_GEN_PUBLIC_ALT */
#if defined(MBEDTLS_ECDH_COMPUTE_SHARED_ALT)
"MBEDTLS_ECDH_COMPUTE_SHARED_ALT",
#endif /* MBEDTLS_ECDH_COMPUTE_SHARED_ALT */
#if defined(MBEDTLS_ECDSA_VERIFY_ALT)
"MBEDTLS_ECDSA_VERIFY_ALT",
#endif /* MBEDTLS_ECDSA_VERIFY_ALT */
#if defined(MBEDTLS_ECDSA_SIGN_ALT)
"MBEDTLS_ECDSA_SIGN_ALT",
#endif /* MBEDTLS_ECDSA_SIGN_ALT */
#if defined(MBEDTLS_ECDSA_GENKEY_ALT)
"MBEDTLS_ECDSA_GENKEY_ALT",
#endif /* MBEDTLS_ECDSA_GENKEY_ALT */
#if defined(MBEDTLS_ECP_INTERNAL_ALT)
"MBEDTLS_ECP_INTERNAL_ALT",
#endif /* MBEDTLS_ECP_INTERNAL_ALT */
#if defined(MBEDTLS_ECP_RANDOMIZE_JAC_ALT)
"MBEDTLS_ECP_RANDOMIZE_JAC_ALT",
#endif /* MBEDTLS_ECP_RANDOMIZE_JAC_ALT */
#if defined(MBEDTLS_ECP_ADD_MIXED_ALT)
"MBEDTLS_ECP_ADD_MIXED_ALT",
#endif /* MBEDTLS_ECP_ADD_MIXED_ALT */
#if defined(MBEDTLS_ECP_DOUBLE_JAC_ALT)
"MBEDTLS_ECP_DOUBLE_JAC_ALT",
#endif /* MBEDTLS_ECP_DOUBLE_JAC_ALT */
#if defined(MBEDTLS_ECP_NORMALIZE_JAC_MANY_ALT)
"MBEDTLS_ECP_NORMALIZE_JAC_MANY_ALT",
#endif /* MBEDTLS_ECP_NORMALIZE_JAC_MANY_ALT */
#if defined(MBEDTLS_ECP_NORMALIZE_JAC_ALT)
"MBEDTLS_ECP_NORMALIZE_JAC_ALT",
#endif /* MBEDTLS_ECP_NORMALIZE_JAC_ALT */
#if defined(MBEDTLS_ECP_DOUBLE_ADD_MXZ_ALT)
"MBEDTLS_ECP_DOUBLE_ADD_MXZ_ALT",
#endif /* MBEDTLS_ECP_DOUBLE_ADD_MXZ_ALT */
#if defined(MBEDTLS_ECP_RANDOMIZE_MXZ_ALT)
"MBEDTLS_ECP_RANDOMIZE_MXZ_ALT",
#endif /* MBEDTLS_ECP_RANDOMIZE_MXZ_ALT */
#if defined(MBEDTLS_ECP_NORMALIZE_MXZ_ALT)
"MBEDTLS_ECP_NORMALIZE_MXZ_ALT",
#endif /* MBEDTLS_ECP_NORMALIZE_MXZ_ALT */
#if defined(MBEDTLS_TEST_NULL_ENTROPY)
"MBEDTLS_TEST_NULL_ENTROPY",
#endif /* MBEDTLS_TEST_NULL_ENTROPY */
#if defined(MBEDTLS_ENTROPY_HARDWARE_ALT) #if defined(MBEDTLS_ENTROPY_HARDWARE_ALT)
"MBEDTLS_ENTROPY_HARDWARE_ALT", "MBEDTLS_ENTROPY_HARDWARE_ALT",
#endif /* MBEDTLS_ENTROPY_HARDWARE_ALT */ #endif /* MBEDTLS_ENTROPY_HARDWARE_ALT */
...@@ -288,6 +366,9 @@ static const char *features[] = { ...@@ -288,6 +366,9 @@ static const char *features[] = {
#if defined(MBEDTLS_ENTROPY_FORCE_SHA256) #if defined(MBEDTLS_ENTROPY_FORCE_SHA256)
"MBEDTLS_ENTROPY_FORCE_SHA256", "MBEDTLS_ENTROPY_FORCE_SHA256",
#endif /* MBEDTLS_ENTROPY_FORCE_SHA256 */ #endif /* MBEDTLS_ENTROPY_FORCE_SHA256 */
#if defined(MBEDTLS_ENTROPY_NV_SEED)
"MBEDTLS_ENTROPY_NV_SEED",
#endif /* MBEDTLS_ENTROPY_NV_SEED */
#if defined(MBEDTLS_MEMORY_DEBUG) #if defined(MBEDTLS_MEMORY_DEBUG)
"MBEDTLS_MEMORY_DEBUG", "MBEDTLS_MEMORY_DEBUG",
#endif /* MBEDTLS_MEMORY_DEBUG */ #endif /* MBEDTLS_MEMORY_DEBUG */
...@@ -312,9 +393,6 @@ static const char *features[] = { ...@@ -312,9 +393,6 @@ static const char *features[] = {
#if defined(MBEDTLS_SHA256_SMALLER) #if defined(MBEDTLS_SHA256_SMALLER)
"MBEDTLS_SHA256_SMALLER", "MBEDTLS_SHA256_SMALLER",
#endif /* MBEDTLS_SHA256_SMALLER */ #endif /* MBEDTLS_SHA256_SMALLER */
#if defined(MBEDTLS_SSL_AEAD_RANDOM_IV)
"MBEDTLS_SSL_AEAD_RANDOM_IV",
#endif /* MBEDTLS_SSL_AEAD_RANDOM_IV */
#if defined(MBEDTLS_SSL_ALL_ALERT_MESSAGES) #if defined(MBEDTLS_SSL_ALL_ALERT_MESSAGES)
"MBEDTLS_SSL_ALL_ALERT_MESSAGES", "MBEDTLS_SSL_ALL_ALERT_MESSAGES",
#endif /* MBEDTLS_SSL_ALL_ALERT_MESSAGES */ #endif /* MBEDTLS_SSL_ALL_ALERT_MESSAGES */
...@@ -453,6 +531,9 @@ static const char *features[] = { ...@@ -453,6 +531,9 @@ static const char *features[] = {
#if defined(MBEDTLS_CIPHER_C) #if defined(MBEDTLS_CIPHER_C)
"MBEDTLS_CIPHER_C", "MBEDTLS_CIPHER_C",
#endif /* MBEDTLS_CIPHER_C */ #endif /* MBEDTLS_CIPHER_C */
#if defined(MBEDTLS_CMAC_C)
"MBEDTLS_CMAC_C",
#endif /* MBEDTLS_CMAC_C */
#if defined(MBEDTLS_CTR_DRBG_C) #if defined(MBEDTLS_CTR_DRBG_C)
"MBEDTLS_CTR_DRBG_C", "MBEDTLS_CTR_DRBG_C",
#endif /* MBEDTLS_CTR_DRBG_C */ #endif /* MBEDTLS_CTR_DRBG_C */
......
...@@ -59,6 +59,11 @@ ...@@ -59,6 +59,11 @@
#define mbedtls_snprintf snprintf #define mbedtls_snprintf snprintf
#endif #endif
#if defined(MBEDTLS_HAVE_TIME)
#include "mbedtls/platform_time.h"
#endif
#if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) #if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32)
#include <windows.h> #include <windows.h>
#else #else
...@@ -75,6 +80,7 @@ ...@@ -75,6 +80,7 @@
#endif #endif
#define CHECK(code) if( ( ret = code ) != 0 ){ return( ret ); } #define CHECK(code) if( ( ret = code ) != 0 ){ return( ret ); }
#define CHECK_RANGE(min, max, val) if( val < min || val > max ){ return( ret ); }
/* /*
* CertificateSerialNumber ::= INTEGER * CertificateSerialNumber ::= INTEGER
...@@ -474,14 +480,117 @@ int mbedtls_x509_get_name( unsigned char **p, const unsigned char *end, ...@@ -474,14 +480,117 @@ int mbedtls_x509_get_name( unsigned char **p, const unsigned char *end,
} }
} }
static int x509_parse_int(unsigned char **p, unsigned n, int *res){ static int x509_parse_int( unsigned char **p, size_t n, int *res )
{
*res = 0; *res = 0;
for( ; n > 0; --n ){
if( ( **p < '0') || ( **p > '9' ) ) return MBEDTLS_ERR_X509_INVALID_DATE; for( ; n > 0; --n )
{
if( ( **p < '0') || ( **p > '9' ) )
return ( MBEDTLS_ERR_X509_INVALID_DATE );
*res *= 10; *res *= 10;
*res += (*(*p)++ - '0'); *res += ( *(*p)++ - '0' );
}
return( 0 );
}
static int x509_date_is_valid(const mbedtls_x509_time *t )
{
int ret = MBEDTLS_ERR_X509_INVALID_DATE;
int month_len;
CHECK_RANGE( 0, 9999, t->year );
CHECK_RANGE( 0, 23, t->hour );
CHECK_RANGE( 0, 59, t->min );
CHECK_RANGE( 0, 59, t->sec );
switch( t->mon )
{
case 1: case 3: case 5: case 7: case 8: case 10: case 12:
month_len = 31;
break;
case 4: case 6: case 9: case 11:
month_len = 30;
break;
case 2:
if( ( !( t->year % 4 ) && t->year % 100 ) ||
!( t->year % 400 ) )
month_len = 29;
else
month_len = 28;
break;
default:
return( ret );
} }
return 0; CHECK_RANGE( 1, month_len, t->day );
return( 0 );
}
/*
* Parse an ASN1_UTC_TIME (yearlen=2) or ASN1_GENERALIZED_TIME (yearlen=4)
* field.
*/
static int x509_parse_time( unsigned char **p, size_t len, size_t yearlen,
mbedtls_x509_time *tm )
{
int ret;
/*
* Minimum length is 10 or 12 depending on yearlen
*/
if ( len < yearlen + 8 )
return ( MBEDTLS_ERR_X509_INVALID_DATE );
len -= yearlen + 8;
/*
* Parse year, month, day, hour, minute
*/
CHECK( x509_parse_int( p, yearlen, &tm->year ) );
if ( 2 == yearlen )
{
if ( tm->year < 50 )
tm->year += 100;
tm->year += 1900;
}
CHECK( x509_parse_int( p, 2, &tm->mon ) );
CHECK( x509_parse_int( p, 2, &tm->day ) );
CHECK( x509_parse_int( p, 2, &tm->hour ) );
CHECK( x509_parse_int( p, 2, &tm->min ) );
/*
* Parse seconds if present
*/
if ( len >= 2 )
{
CHECK( x509_parse_int( p, 2, &tm->sec ) );
len -= 2;
}
else
return ( MBEDTLS_ERR_X509_INVALID_DATE );
/*
* Parse trailing 'Z' if present
*/
if ( 1 == len && 'Z' == **p )
{
(*p)++;
len--;
}
/*
* We should have parsed all characters at this point
*/
if ( 0 != len )
return ( MBEDTLS_ERR_X509_INVALID_DATE );
CHECK( x509_date_is_valid( tm ) );
return ( 0 );
} }
/* /*
...@@ -490,10 +599,10 @@ static int x509_parse_int(unsigned char **p, unsigned n, int *res){ ...@@ -490,10 +599,10 @@ static int x509_parse_int(unsigned char **p, unsigned n, int *res){
* generalTime GeneralizedTime } * generalTime GeneralizedTime }
*/ */
int mbedtls_x509_get_time( unsigned char **p, const unsigned char *end, int mbedtls_x509_get_time( unsigned char **p, const unsigned char *end,
mbedtls_x509_time *time ) mbedtls_x509_time *tm )
{ {
int ret; int ret;
size_t len; size_t len, year_len;
unsigned char tag; unsigned char tag;
if( ( end - *p ) < 1 ) if( ( end - *p ) < 1 )
...@@ -503,67 +612,38 @@ int mbedtls_x509_get_time( unsigned char **p, const unsigned char *end, ...@@ -503,67 +612,38 @@ int mbedtls_x509_get_time( unsigned char **p, const unsigned char *end,
tag = **p; tag = **p;
if( tag == MBEDTLS_ASN1_UTC_TIME ) if( tag == MBEDTLS_ASN1_UTC_TIME )
{ year_len = 2;
(*p)++;
ret = mbedtls_asn1_get_len( p, end, &len );
if( ret != 0 )
return( MBEDTLS_ERR_X509_INVALID_DATE + ret );
CHECK( x509_parse_int( p, 2, &time->year ) );
CHECK( x509_parse_int( p, 2, &time->mon ) );
CHECK( x509_parse_int( p, 2, &time->day ) );
CHECK( x509_parse_int( p, 2, &time->hour ) );
CHECK( x509_parse_int( p, 2, &time->min ) );
if( len > 10 )
CHECK( x509_parse_int( p, 2, &time->sec ) );
if( len > 12 && *(*p)++ != 'Z' )
return( MBEDTLS_ERR_X509_INVALID_DATE );
time->year += 100 * ( time->year < 50 );
time->year += 1900;
return( 0 );
}
else if( tag == MBEDTLS_ASN1_GENERALIZED_TIME ) else if( tag == MBEDTLS_ASN1_GENERALIZED_TIME )
{ year_len = 4;
else
return( MBEDTLS_ERR_X509_INVALID_DATE +
MBEDTLS_ERR_ASN1_UNEXPECTED_TAG );
(*p)++; (*p)++;
ret = mbedtls_asn1_get_len( p, end, &len ); ret = mbedtls_asn1_get_len( p, end, &len );
if( ret != 0 ) if( ret != 0 )
return( MBEDTLS_ERR_X509_INVALID_DATE + ret ); return( MBEDTLS_ERR_X509_INVALID_DATE + ret );
CHECK( x509_parse_int( p, 4, &time->year ) ); return x509_parse_time( p, len, year_len, tm );
CHECK( x509_parse_int( p, 2, &time->mon ) );
CHECK( x509_parse_int( p, 2, &time->day ) );
CHECK( x509_parse_int( p, 2, &time->hour ) );
CHECK( x509_parse_int( p, 2, &time->min ) );
if( len > 12 )
CHECK( x509_parse_int( p, 2, &time->sec ) );
if( len > 14 && *(*p)++ != 'Z' )
return( MBEDTLS_ERR_X509_INVALID_DATE );
return( 0 );
}
else
return( MBEDTLS_ERR_X509_INVALID_DATE +
MBEDTLS_ERR_ASN1_UNEXPECTED_TAG );
} }
int mbedtls_x509_get_sig( unsigned char **p, const unsigned char *end, mbedtls_x509_buf *sig ) int mbedtls_x509_get_sig( unsigned char **p, const unsigned char *end, mbedtls_x509_buf *sig )
{ {
int ret; int ret;
size_t len; size_t len;
int tag_type;
if( ( end - *p ) < 1 ) if( ( end - *p ) < 1 )
return( MBEDTLS_ERR_X509_INVALID_SIGNATURE + return( MBEDTLS_ERR_X509_INVALID_SIGNATURE +
MBEDTLS_ERR_ASN1_OUT_OF_DATA ); MBEDTLS_ERR_ASN1_OUT_OF_DATA );
sig->tag = **p; tag_type = **p;
if( ( ret = mbedtls_asn1_get_bitstring_null( p, end, &len ) ) != 0 ) if( ( ret = mbedtls_asn1_get_bitstring_null( p, end, &len ) ) != 0 )
return( MBEDTLS_ERR_X509_INVALID_SIGNATURE + ret ); return( MBEDTLS_ERR_X509_INVALID_SIGNATURE + ret );
sig->tag = tag_type;
sig->len = len; sig->len = len;
sig->p = *p; sig->p = *p;
...@@ -622,7 +702,7 @@ int mbedtls_x509_get_sig_alg( const mbedtls_x509_buf *sig_oid, const mbedtls_x50 ...@@ -622,7 +702,7 @@ int mbedtls_x509_get_sig_alg( const mbedtls_x509_buf *sig_oid, const mbedtls_x50
/* /*
* X.509 Extensions (No parsing of extensions, pointer should * X.509 Extensions (No parsing of extensions, pointer should
* be either manually updated or extensions should be parsed! * be either manually updated or extensions should be parsed!)
*/ */
int mbedtls_x509_get_ext( unsigned char **p, const unsigned char *end, int mbedtls_x509_get_ext( unsigned char **p, const unsigned char *end,
mbedtls_x509_buf *ext, int tag ) mbedtls_x509_buf *ext, int tag )
...@@ -843,7 +923,7 @@ static int x509_get_current_time( mbedtls_x509_time *now ) ...@@ -843,7 +923,7 @@ static int x509_get_current_time( mbedtls_x509_time *now )
static int x509_get_current_time( mbedtls_x509_time *now ) static int x509_get_current_time( mbedtls_x509_time *now )
{ {
struct tm *lt; struct tm *lt;
time_t tt; mbedtls_time_t tt;
int ret = 0; int ret = 0;
#if defined(MBEDTLS_THREADING_C) #if defined(MBEDTLS_THREADING_C)
...@@ -851,7 +931,7 @@ static int x509_get_current_time( mbedtls_x509_time *now ) ...@@ -851,7 +931,7 @@ static int x509_get_current_time( mbedtls_x509_time *now )
return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); return( MBEDTLS_ERR_THREADING_MUTEX_ERROR );
#endif #endif
tt = time( NULL ); tt = mbedtls_time( NULL );
lt = gmtime( &tt ); lt = gmtime( &tt );
if( lt == NULL ) if( lt == NULL )
...@@ -961,7 +1041,7 @@ int mbedtls_x509_time_is_future( const mbedtls_x509_time *from ) ...@@ -961,7 +1041,7 @@ int mbedtls_x509_time_is_future( const mbedtls_x509_time *from )
*/ */
int mbedtls_x509_self_test( int verbose ) int mbedtls_x509_self_test( int verbose )
{ {
#if defined(MBEDTLS_CERTS_C) && defined(MBEDTLS_SHA1_C) #if defined(MBEDTLS_CERTS_C) && defined(MBEDTLS_SHA256_C)
int ret; int ret;
uint32_t flags; uint32_t flags;
mbedtls_x509_crt cacert; mbedtls_x509_crt cacert;
......
...@@ -30,7 +30,7 @@ ...@@ -30,7 +30,7 @@
#include "mbedtls/x509.h" #include "mbedtls/x509.h"
#include "mbedtls/asn1write.h" #include "mbedtls/asn1write.h"
#include "mbedtls/oid.h" #include "mbedtls/oid.h"
#include "c_types.h"
#include <string.h> #include <string.h>
typedef struct { typedef struct {
...@@ -41,7 +41,7 @@ typedef struct { ...@@ -41,7 +41,7 @@ typedef struct {
#define ADD_STRLEN( s ) s, sizeof( s ) - 1 #define ADD_STRLEN( s ) s, sizeof( s ) - 1
static const x509_attr_descriptor_t x509_attrs[] ICACHE_RODATA_ATTR STORE_ATTR = static const x509_attr_descriptor_t x509_attrs[] =
{ {
{ ADD_STRLEN( "CN" ), MBEDTLS_OID_AT_CN }, { ADD_STRLEN( "CN" ), MBEDTLS_OID_AT_CN },
{ ADD_STRLEN( "commonName" ), MBEDTLS_OID_AT_CN }, { ADD_STRLEN( "commonName" ), MBEDTLS_OID_AT_CN },
......
...@@ -352,14 +352,14 @@ int mbedtls_x509_crl_parse_der( mbedtls_x509_crl *chain, ...@@ -352,14 +352,14 @@ int mbedtls_x509_crl_parse_der( mbedtls_x509_crl *chain,
return( ret ); return( ret );
} }
crl->version++; if( crl->version < 0 || crl->version > 1 )
if( crl->version > 2 )
{ {
mbedtls_x509_crl_free( crl ); mbedtls_x509_crl_free( crl );
return( MBEDTLS_ERR_X509_UNKNOWN_VERSION ); return( MBEDTLS_ERR_X509_UNKNOWN_VERSION );
} }
crl->version++;
if( ( ret = mbedtls_x509_get_sig_alg( &crl->sig_oid, &sig_params1, if( ( ret = mbedtls_x509_get_sig_alg( &crl->sig_oid, &sig_params1,
&crl->sig_md, &crl->sig_pk, &crl->sig_md, &crl->sig_pk,
&crl->sig_opts ) ) != 0 ) &crl->sig_opts ) ) != 0 )
...@@ -502,7 +502,8 @@ int mbedtls_x509_crl_parse( mbedtls_x509_crl *chain, const unsigned char *buf, s ...@@ -502,7 +502,8 @@ int mbedtls_x509_crl_parse( mbedtls_x509_crl *chain, const unsigned char *buf, s
{ {
mbedtls_pem_init( &pem ); mbedtls_pem_init( &pem );
/* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */ // Avoid calling mbedtls_pem_read_buffer() on non-null-terminated
// string
if( buflen == 0 || buf[buflen - 1] != '\0' ) if( buflen == 0 || buf[buflen - 1] != '\0' )
ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT; ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT;
else else
...@@ -524,16 +525,17 @@ int mbedtls_x509_crl_parse( mbedtls_x509_crl *chain, const unsigned char *buf, s ...@@ -524,16 +525,17 @@ int mbedtls_x509_crl_parse( mbedtls_x509_crl *chain, const unsigned char *buf, s
if( ( ret = mbedtls_x509_crl_parse_der( chain, if( ( ret = mbedtls_x509_crl_parse_der( chain,
pem.buf, pem.buflen ) ) != 0 ) pem.buf, pem.buflen ) ) != 0 )
{ {
mbedtls_pem_free( &pem );
return( ret ); return( ret );
} }
mbedtls_pem_free( &pem );
} }
else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) else if( is_pem )
{ {
mbedtls_pem_free( &pem ); mbedtls_pem_free( &pem );
return( ret ); return( ret );
} }
mbedtls_pem_free( &pem );
} }
/* In the PEM case, buflen is 1 at the end, for the terminated NULL byte. /* In the PEM case, buflen is 1 at the end, for the terminated NULL byte.
* And a valid CRL cannot be less than 1 byte anyway. */ * And a valid CRL cannot be less than 1 byte anyway. */
......
...@@ -83,33 +83,28 @@ static void mbedtls_zeroize( void *v, size_t n ) { ...@@ -83,33 +83,28 @@ static void mbedtls_zeroize( void *v, size_t n ) {
/* /*
* Default profile * Default profile
*/ */
const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_default ICACHE_RODATA_ATTR = const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_default =
{ {
/* Hashes from SHA-1 and above */ #if defined(MBEDTLS_TLS_DEFAULT_ALLOW_SHA1_IN_CERTIFICATES)
/* Allow SHA-1 (weak, but still safe in controlled environments) */
MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA1 ) | MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA1 ) |
MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_RIPEMD160 ) | #endif
/* Only SHA-2 hashes */
MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA224 ) | MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA224 ) |
MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA256 ) | MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA256 ) |
MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA384 ) | MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA384 ) |
MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA512 ), MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA512 ),
0xFFFFFFF, /* Any PK alg */ 0xFFFFFFF, /* Any PK alg */
0xFFFFFFF, /* Any curve */ 0xFFFFFFF, /* Any curve */
#if defined(ESP8266_PLATFORM)
512,
#else
2048, 2048,
#endif
}; };
/* /*
* Next-default profile * Next-default profile
*/ */
const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_next ICACHE_RODATA_ATTR = const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_next =
{ {
/* Hashes from SHA-256 and above */ /* Hashes from SHA-256 and above */
#if defined(ESP8266_PLATFORM)
MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA1 ) |
#endif
MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA256 ) | MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA256 ) |
MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA384 ) | MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA384 ) |
MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA512 ), MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA512 ),
...@@ -126,22 +121,15 @@ const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_next ICACHE_RODATA_ATTR ...@@ -126,22 +121,15 @@ const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_next ICACHE_RODATA_ATTR
#else #else
0, 0,
#endif #endif
#if defined(ESP8266_PLATFORM)
512,
#else
2048, 2048,
#endif
}; };
/* /*
* NSA Suite B Profile * NSA Suite B Profile
*/ */
const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_suiteb ICACHE_RODATA_ATTR = const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_suiteb =
{ {
/* Only SHA-256 and 384 */ /* Only SHA-256 and 384 */
#if defined(ESP8266_PLATFORM)
MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA1 ) |
#endif
MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA256 ) | MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA256 ) |
MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA384 ), MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA384 ),
/* Only ECDSA */ /* Only ECDSA */
...@@ -530,9 +518,6 @@ static int x509_get_subject_alt_name( unsigned char **p, ...@@ -530,9 +518,6 @@ static int x509_get_subject_alt_name( unsigned char **p,
/* /*
* X.509 v3 extensions * X.509 v3 extensions
* *
* TODO: Perform all of the basic constraints tests required by the RFC
* TODO: Set values for undetected extensions to a sane default?
*
*/ */
static int x509_get_crt_ext( unsigned char **p, static int x509_get_crt_ext( unsigned char **p,
const unsigned char *end, const unsigned char *end,
...@@ -694,14 +679,9 @@ static int x509_crt_parse_der_core( mbedtls_x509_crt *crt, const unsigned char * ...@@ -694,14 +679,9 @@ static int x509_crt_parse_der_core( mbedtls_x509_crt *crt, const unsigned char *
if( crt == NULL || buf == NULL ) if( crt == NULL || buf == NULL )
return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); return( MBEDTLS_ERR_X509_BAD_INPUT_DATA );
p = mbedtls_calloc( 1, len = buflen ); // Use the original buffer until we figure out actual length
if( p == NULL ) p = (unsigned char*) buf;
return( MBEDTLS_ERR_X509_ALLOC_FAILED ); len = buflen;
memcpy( p, buf, buflen );
crt->raw.p = p;
crt->raw.len = len;
end = p + len; end = p + len;
/* /*
...@@ -725,6 +705,18 @@ static int x509_crt_parse_der_core( mbedtls_x509_crt *crt, const unsigned char * ...@@ -725,6 +705,18 @@ static int x509_crt_parse_der_core( mbedtls_x509_crt *crt, const unsigned char *
} }
crt_end = p + len; crt_end = p + len;
// Create and populate a new buffer for the raw field
crt->raw.len = crt_end - buf;
crt->raw.p = p = mbedtls_calloc( 1, crt->raw.len );
if( p == NULL )
return( MBEDTLS_ERR_X509_ALLOC_FAILED );
memcpy( p, buf, crt->raw.len );
// Direct pointers to the new buffer
p += crt->raw.len - len;
end = crt_end = p + len;
/* /*
* TBSCertificate ::= SEQUENCE { * TBSCertificate ::= SEQUENCE {
*/ */
...@@ -756,14 +748,14 @@ static int x509_crt_parse_der_core( mbedtls_x509_crt *crt, const unsigned char * ...@@ -756,14 +748,14 @@ static int x509_crt_parse_der_core( mbedtls_x509_crt *crt, const unsigned char *
return( ret ); return( ret );
} }
crt->version++; if( crt->version < 0 || crt->version > 2 )
if( crt->version > 3 )
{ {
mbedtls_x509_crt_free( crt ); mbedtls_x509_crt_free( crt );
return( MBEDTLS_ERR_X509_UNKNOWN_VERSION ); return( MBEDTLS_ERR_X509_UNKNOWN_VERSION );
} }
crt->version++;
if( ( ret = mbedtls_x509_get_sig_alg( &crt->sig_oid, &sig_params1, if( ( ret = mbedtls_x509_get_sig_alg( &crt->sig_oid, &sig_params1,
&crt->sig_md, &crt->sig_pk, &crt->sig_md, &crt->sig_pk,
&crt->sig_opts ) ) != 0 ) &crt->sig_opts ) ) != 0 )
...@@ -979,8 +971,10 @@ int mbedtls_x509_crt_parse_der( mbedtls_x509_crt *chain, const unsigned char *bu ...@@ -979,8 +971,10 @@ int mbedtls_x509_crt_parse_der( mbedtls_x509_crt *chain, const unsigned char *bu
*/ */
int mbedtls_x509_crt_parse( mbedtls_x509_crt *chain, const unsigned char *buf, size_t buflen ) int mbedtls_x509_crt_parse( mbedtls_x509_crt *chain, const unsigned char *buf, size_t buflen )
{ {
#if defined(MBEDTLS_PEM_PARSE_C)
int success = 0, first_error = 0, total_failed = 0; int success = 0, first_error = 0, total_failed = 0;
int buf_format = MBEDTLS_X509_FORMAT_DER; int buf_format = MBEDTLS_X509_FORMAT_DER;
#endif
/* /*
* Check for valid input * Check for valid input
...@@ -998,10 +992,12 @@ int mbedtls_x509_crt_parse( mbedtls_x509_crt *chain, const unsigned char *buf, s ...@@ -998,10 +992,12 @@ int mbedtls_x509_crt_parse( mbedtls_x509_crt *chain, const unsigned char *buf, s
{ {
buf_format = MBEDTLS_X509_FORMAT_PEM; buf_format = MBEDTLS_X509_FORMAT_PEM;
} }
#endif
if( buf_format == MBEDTLS_X509_FORMAT_DER ) if( buf_format == MBEDTLS_X509_FORMAT_DER )
return mbedtls_x509_crt_parse_der( chain, buf, buflen ); return mbedtls_x509_crt_parse_der( chain, buf, buflen );
#else
return mbedtls_x509_crt_parse_der( chain, buf, buflen );
#endif
#if defined(MBEDTLS_PEM_PARSE_C) #if defined(MBEDTLS_PEM_PARSE_C)
if( buf_format == MBEDTLS_X509_FORMAT_PEM ) if( buf_format == MBEDTLS_X509_FORMAT_PEM )
...@@ -1074,7 +1070,6 @@ int mbedtls_x509_crt_parse( mbedtls_x509_crt *chain, const unsigned char *buf, s ...@@ -1074,7 +1070,6 @@ int mbedtls_x509_crt_parse( mbedtls_x509_crt *chain, const unsigned char *buf, s
success = 1; success = 1;
} }
} }
#endif /* MBEDTLS_PEM_PARSE_C */
if( success ) if( success )
return( total_failed ); return( total_failed );
...@@ -1082,6 +1077,7 @@ int mbedtls_x509_crt_parse( mbedtls_x509_crt *chain, const unsigned char *buf, s ...@@ -1082,6 +1077,7 @@ int mbedtls_x509_crt_parse( mbedtls_x509_crt *chain, const unsigned char *buf, s
return( first_error ); return( first_error );
else else
return( MBEDTLS_ERR_X509_CERT_UNKNOWN_FORMAT ); return( MBEDTLS_ERR_X509_CERT_UNKNOWN_FORMAT );
#endif /* MBEDTLS_PEM_PARSE_C */
} }
#if defined(MBEDTLS_FS_IO) #if defined(MBEDTLS_FS_IO)
...@@ -1128,7 +1124,7 @@ int mbedtls_x509_crt_parse_path( mbedtls_x509_crt *chain, const char *path ) ...@@ -1128,7 +1124,7 @@ int mbedtls_x509_crt_parse_path( mbedtls_x509_crt *chain, const char *path )
p = filename + len; p = filename + len;
filename[len++] = '*'; filename[len++] = '*';
w_ret = MultiByteToWideChar( CP_ACP, 0, filename, len, szDir, w_ret = MultiByteToWideChar( CP_ACP, 0, filename, (int)len, szDir,
MAX_PATH - 3 ); MAX_PATH - 3 );
if( w_ret == 0 ) if( w_ret == 0 )
return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); return( MBEDTLS_ERR_X509_BAD_INPUT_DATA );
...@@ -1150,7 +1146,10 @@ int mbedtls_x509_crt_parse_path( mbedtls_x509_crt *chain, const char *path ) ...@@ -1150,7 +1146,10 @@ int mbedtls_x509_crt_parse_path( mbedtls_x509_crt *chain, const char *path )
p, (int) len - 1, p, (int) len - 1,
NULL, NULL ); NULL, NULL );
if( w_ret == 0 ) if( w_ret == 0 )
return( MBEDTLS_ERR_X509_FILE_IO_ERROR ); {
ret = MBEDTLS_ERR_X509_FILE_IO_ERROR;
goto cleanup;
}
w_ret = mbedtls_x509_crt_parse_file( chain, filename ); w_ret = mbedtls_x509_crt_parse_file( chain, filename );
if( w_ret < 0 ) if( w_ret < 0 )
...@@ -1163,32 +1162,39 @@ int mbedtls_x509_crt_parse_path( mbedtls_x509_crt *chain, const char *path ) ...@@ -1163,32 +1162,39 @@ int mbedtls_x509_crt_parse_path( mbedtls_x509_crt *chain, const char *path )
if( GetLastError() != ERROR_NO_MORE_FILES ) if( GetLastError() != ERROR_NO_MORE_FILES )
ret = MBEDTLS_ERR_X509_FILE_IO_ERROR; ret = MBEDTLS_ERR_X509_FILE_IO_ERROR;
cleanup:
FindClose( hFind ); FindClose( hFind );
#else /* _WIN32 */ #else /* _WIN32 */
int t_ret; int t_ret;
int snp_ret;
struct stat sb; struct stat sb;
struct dirent *entry; struct dirent *entry;
char entry_name[255]; char entry_name[MBEDTLS_X509_MAX_FILE_PATH_LEN];
DIR *dir = opendir( path ); DIR *dir = opendir( path );
if( dir == NULL ) if( dir == NULL )
return( MBEDTLS_ERR_X509_FILE_IO_ERROR ); return( MBEDTLS_ERR_X509_FILE_IO_ERROR );
#if defined(MBEDTLS_THREADING_PTHREAD) #if defined(MBEDTLS_THREADING_C)
if( ( ret = mbedtls_mutex_lock( &mbedtls_threading_readdir_mutex ) ) != 0 ) if( ( ret = mbedtls_mutex_lock( &mbedtls_threading_readdir_mutex ) ) != 0 )
{ {
closedir( dir ); closedir( dir );
return( ret ); return( ret );
} }
#endif #endif /* MBEDTLS_THREADING_C */
while( ( entry = readdir( dir ) ) != NULL ) while( ( entry = readdir( dir ) ) != NULL )
{ {
mbedtls_snprintf( entry_name, sizeof entry_name, "%s/%s", path, entry->d_name ); snp_ret = mbedtls_snprintf( entry_name, sizeof entry_name,
"%s/%s", path, entry->d_name );
if( stat( entry_name, &sb ) == -1 ) if( snp_ret < 0 || (size_t)snp_ret >= sizeof entry_name )
{
ret = MBEDTLS_ERR_X509_BUFFER_TOO_SMALL;
goto cleanup;
}
else if( stat( entry_name, &sb ) == -1 )
{ {
closedir( dir );
ret = MBEDTLS_ERR_X509_FILE_IO_ERROR; ret = MBEDTLS_ERR_X509_FILE_IO_ERROR;
goto cleanup; goto cleanup;
} }
...@@ -1204,13 +1210,14 @@ int mbedtls_x509_crt_parse_path( mbedtls_x509_crt *chain, const char *path ) ...@@ -1204,13 +1210,14 @@ int mbedtls_x509_crt_parse_path( mbedtls_x509_crt *chain, const char *path )
else else
ret += t_ret; ret += t_ret;
} }
closedir( dir );
cleanup: cleanup:
#if defined(MBEDTLS_THREADING_PTHREAD) closedir( dir );
#if defined(MBEDTLS_THREADING_C)
if( mbedtls_mutex_unlock( &mbedtls_threading_readdir_mutex ) != 0 ) if( mbedtls_mutex_unlock( &mbedtls_threading_readdir_mutex ) != 0 )
ret = MBEDTLS_ERR_THREADING_MUTEX_ERROR; ret = MBEDTLS_ERR_THREADING_MUTEX_ERROR;
#endif #endif /* MBEDTLS_THREADING_C */
#endif /* _WIN32 */ #endif /* _WIN32 */
...@@ -1363,6 +1370,14 @@ int mbedtls_x509_crt_info( char *buf, size_t size, const char *prefix, ...@@ -1363,6 +1370,14 @@ int mbedtls_x509_crt_info( char *buf, size_t size, const char *prefix,
p = buf; p = buf;
n = size; n = size;
if( NULL == crt )
{
ret = mbedtls_snprintf( p, n, "\nCertificate is uninitialised!\n" );
MBEDTLS_X509_SAFE_SNPRINTF;
return( (int) ( size - n ) );
}
ret = mbedtls_snprintf( p, n, "%scert. version : %d\n", ret = mbedtls_snprintf( p, n, "%scert. version : %d\n",
prefix, crt->version ); prefix, crt->version );
MBEDTLS_X509_SAFE_SNPRINTF; MBEDTLS_X509_SAFE_SNPRINTF;
...@@ -1481,7 +1496,6 @@ struct x509_crt_verify_string { ...@@ -1481,7 +1496,6 @@ struct x509_crt_verify_string {
const char *string; const char *string;
}; };
#if 0
static const struct x509_crt_verify_string x509_crt_verify_strings[] = { static const struct x509_crt_verify_string x509_crt_verify_strings[] = {
{ MBEDTLS_X509_BADCERT_EXPIRED, "The certificate validity has expired" }, { MBEDTLS_X509_BADCERT_EXPIRED, "The certificate validity has expired" },
{ MBEDTLS_X509_BADCERT_REVOKED, "The certificate has been revoked (is on a CRL)" }, { MBEDTLS_X509_BADCERT_REVOKED, "The certificate has been revoked (is on a CRL)" },
...@@ -1505,31 +1519,6 @@ static const struct x509_crt_verify_string x509_crt_verify_strings[] = { ...@@ -1505,31 +1519,6 @@ static const struct x509_crt_verify_string x509_crt_verify_strings[] = {
{ MBEDTLS_X509_BADCRL_BAD_KEY, "The CRL is signed with an unacceptable key (eg bad curve, RSA too short)." }, { MBEDTLS_X509_BADCRL_BAD_KEY, "The CRL is signed with an unacceptable key (eg bad curve, RSA too short)." },
{ 0, NULL } { 0, NULL }
}; };
#else
static const struct x509_crt_verify_string x509_crt_verify_strings[] = {
{ MBEDTLS_X509_BADCERT_EXPIRED, NULL },
{ MBEDTLS_X509_BADCERT_REVOKED, NULL },
{ MBEDTLS_X509_BADCERT_CN_MISMATCH, NULL },
{ MBEDTLS_X509_BADCERT_NOT_TRUSTED, NULL },
{ MBEDTLS_X509_BADCRL_NOT_TRUSTED, NULL },
{ MBEDTLS_X509_BADCRL_EXPIRED, NULL },
{ MBEDTLS_X509_BADCERT_MISSING, NULL },
{ MBEDTLS_X509_BADCERT_SKIP_VERIFY, NULL },
{ MBEDTLS_X509_BADCERT_OTHER, NULL },
{ MBEDTLS_X509_BADCERT_FUTURE, NULL },
{ MBEDTLS_X509_BADCRL_FUTURE, NULL },
{ MBEDTLS_X509_BADCERT_KEY_USAGE, NULL },
{ MBEDTLS_X509_BADCERT_EXT_KEY_USAGE, NULL },
{ MBEDTLS_X509_BADCERT_NS_CERT_TYPE, NULL },
{ MBEDTLS_X509_BADCERT_BAD_MD, NULL },
{ MBEDTLS_X509_BADCERT_BAD_PK, NULL },
{ MBEDTLS_X509_BADCERT_BAD_KEY, NULL },
{ MBEDTLS_X509_BADCRL_BAD_MD, NULL },
{ MBEDTLS_X509_BADCRL_BAD_PK, NULL },
{ MBEDTLS_X509_BADCRL_BAD_KEY, NULL },
{ 0, NULL }
};
#endif
int mbedtls_x509_crt_verify_info( char *buf, size_t size, const char *prefix, int mbedtls_x509_crt_verify_info( char *buf, size_t size, const char *prefix,
uint32_t flags ) uint32_t flags )
...@@ -1640,7 +1629,8 @@ int mbedtls_x509_crt_is_revoked( const mbedtls_x509_crt *crt, const mbedtls_x509 ...@@ -1640,7 +1629,8 @@ int mbedtls_x509_crt_is_revoked( const mbedtls_x509_crt *crt, const mbedtls_x509
} }
/* /*
* Check that the given certificate is valid according to the CRL. * Check that the given certificate is not revoked according to the CRL.
* Skip validation is no CRL for the given CA is present.
*/ */
static int x509_crt_verifycrl( mbedtls_x509_crt *crt, mbedtls_x509_crt *ca, static int x509_crt_verifycrl( mbedtls_x509_crt *crt, mbedtls_x509_crt *ca,
mbedtls_x509_crl *crl_list, mbedtls_x509_crl *crl_list,
...@@ -1653,12 +1643,6 @@ static int x509_crt_verifycrl( mbedtls_x509_crt *crt, mbedtls_x509_crt *ca, ...@@ -1653,12 +1643,6 @@ static int x509_crt_verifycrl( mbedtls_x509_crt *crt, mbedtls_x509_crt *ca,
if( ca == NULL ) if( ca == NULL )
return( flags ); return( flags );
/*
* TODO: What happens if no CRL is present?
* Suggestion: Revocation state should be unknown if no CRL is present.
* For backwards compatibility this is not yet implemented.
*/
while( crl_list != NULL ) while( crl_list != NULL )
{ {
if( crl_list->version == 0 || if( crl_list->version == 0 ||
...@@ -1926,6 +1910,7 @@ static int x509_crt_verify_top( ...@@ -1926,6 +1910,7 @@ static int x509_crt_verify_top(
int check_path_cnt; int check_path_cnt;
unsigned char hash[MBEDTLS_MD_MAX_SIZE]; unsigned char hash[MBEDTLS_MD_MAX_SIZE];
const mbedtls_md_info_t *md_info; const mbedtls_md_info_t *md_info;
mbedtls_x509_crt *future_past_ca = NULL;
if( mbedtls_x509_time_is_past( &child->valid_to ) ) if( mbedtls_x509_time_is_past( &child->valid_to ) )
*flags |= MBEDTLS_X509_BADCERT_EXPIRED; *flags |= MBEDTLS_X509_BADCERT_EXPIRED;
...@@ -1987,6 +1972,20 @@ static int x509_crt_verify_top( ...@@ -1987,6 +1972,20 @@ static int x509_crt_verify_top(
continue; continue;
} }
if( mbedtls_x509_time_is_past( &trust_ca->valid_to ) ||
mbedtls_x509_time_is_future( &trust_ca->valid_from ) )
{
if ( future_past_ca == NULL )
future_past_ca = trust_ca;
continue;
}
break;
}
if( trust_ca != NULL || ( trust_ca = future_past_ca ) != NULL )
{
/* /*
* Top of chain is signed by a trusted CA * Top of chain is signed by a trusted CA
*/ */
...@@ -1994,8 +1993,6 @@ static int x509_crt_verify_top( ...@@ -1994,8 +1993,6 @@ static int x509_crt_verify_top(
if( x509_profile_check_key( profile, child->sig_pk, &trust_ca->pk ) != 0 ) if( x509_profile_check_key( profile, child->sig_pk, &trust_ca->pk ) != 0 )
*flags |= MBEDTLS_X509_BADCERT_BAD_KEY; *flags |= MBEDTLS_X509_BADCERT_BAD_KEY;
break;
} }
/* /*
...@@ -2064,8 +2061,8 @@ static int x509_crt_verify_child( ...@@ -2064,8 +2061,8 @@ static int x509_crt_verify_child(
/* path_cnt is 0 for the first intermediate CA */ /* path_cnt is 0 for the first intermediate CA */
if( 1 + path_cnt > MBEDTLS_X509_MAX_INTERMEDIATE_CA ) if( 1 + path_cnt > MBEDTLS_X509_MAX_INTERMEDIATE_CA )
{ {
*flags |= MBEDTLS_X509_BADCERT_NOT_TRUSTED; /* return immediately as the goal is to avoid unbounded recursion */
return( MBEDTLS_ERR_X509_CERT_VERIFY_FAILED ); return( MBEDTLS_ERR_X509_FATAL_ERROR );
} }
if( mbedtls_x509_time_is_past( &child->valid_to ) ) if( mbedtls_x509_time_is_past( &child->valid_to ) )
...@@ -2209,11 +2206,14 @@ int mbedtls_x509_crt_verify_with_profile( mbedtls_x509_crt *crt, ...@@ -2209,11 +2206,14 @@ int mbedtls_x509_crt_verify_with_profile( mbedtls_x509_crt *crt,
mbedtls_x509_sequence *cur = NULL; mbedtls_x509_sequence *cur = NULL;
mbedtls_pk_type_t pk_type; mbedtls_pk_type_t pk_type;
if( profile == NULL )
return( MBEDTLS_ERR_X509_BAD_INPUT_DATA );
*flags = 0; *flags = 0;
if( profile == NULL )
{
ret = MBEDTLS_ERR_X509_BAD_INPUT_DATA;
goto exit;
}
if( cn != NULL ) if( cn != NULL )
{ {
name = &crt->subject; name = &crt->subject;
...@@ -2287,7 +2287,7 @@ int mbedtls_x509_crt_verify_with_profile( mbedtls_x509_crt *crt, ...@@ -2287,7 +2287,7 @@ int mbedtls_x509_crt_verify_with_profile( mbedtls_x509_crt *crt,
ret = x509_crt_verify_top( crt, parent, ca_crl, profile, ret = x509_crt_verify_top( crt, parent, ca_crl, profile,
pathlen, selfsigned, flags, f_vrfy, p_vrfy ); pathlen, selfsigned, flags, f_vrfy, p_vrfy );
if( ret != 0 ) if( ret != 0 )
return( ret ); goto exit;
} }
else else
{ {
...@@ -2302,15 +2302,28 @@ int mbedtls_x509_crt_verify_with_profile( mbedtls_x509_crt *crt, ...@@ -2302,15 +2302,28 @@ int mbedtls_x509_crt_verify_with_profile( mbedtls_x509_crt *crt,
ret = x509_crt_verify_child( crt, parent, trust_ca, ca_crl, profile, ret = x509_crt_verify_child( crt, parent, trust_ca, ca_crl, profile,
pathlen, selfsigned, flags, f_vrfy, p_vrfy ); pathlen, selfsigned, flags, f_vrfy, p_vrfy );
if( ret != 0 ) if( ret != 0 )
return( ret ); goto exit;
} }
else else
{ {
ret = x509_crt_verify_top( crt, trust_ca, ca_crl, profile, ret = x509_crt_verify_top( crt, trust_ca, ca_crl, profile,
pathlen, selfsigned, flags, f_vrfy, p_vrfy ); pathlen, selfsigned, flags, f_vrfy, p_vrfy );
if( ret != 0 ) if( ret != 0 )
return( ret ); goto exit;
}
} }
exit:
/* prevent misuse of the vrfy callback - VERIFY_FAILED would be ignored by
* the SSL module for authmode optional, but non-zero return from the
* callback means a fatal error so it shouldn't be ignored */
if( ret == MBEDTLS_ERR_X509_CERT_VERIFY_FAILED )
ret = MBEDTLS_ERR_X509_FATAL_ERROR;
if( ret != 0 )
{
*flags = (uint32_t) -1;
return( ret );
} }
if( *flags != 0 ) if( *flags != 0 )
......
...@@ -104,7 +104,7 @@ int mbedtls_x509_csr_parse_der( mbedtls_x509_csr *csr, ...@@ -104,7 +104,7 @@ int mbedtls_x509_csr_parse_der( mbedtls_x509_csr *csr,
/* /*
* Check for valid input * Check for valid input
*/ */
if( csr == NULL || buf == NULL ) if( csr == NULL || buf == NULL || buflen == 0 )
return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); return( MBEDTLS_ERR_X509_BAD_INPUT_DATA );
mbedtls_x509_csr_init( csr ); mbedtls_x509_csr_init( csr );
...@@ -168,14 +168,14 @@ int mbedtls_x509_csr_parse_der( mbedtls_x509_csr *csr, ...@@ -168,14 +168,14 @@ int mbedtls_x509_csr_parse_der( mbedtls_x509_csr *csr,
return( ret ); return( ret );
} }
csr->version++; if( csr->version != 0 )
if( csr->version != 1 )
{ {
mbedtls_x509_csr_free( csr ); mbedtls_x509_csr_free( csr );
return( MBEDTLS_ERR_X509_UNKNOWN_VERSION ); return( MBEDTLS_ERR_X509_UNKNOWN_VERSION );
} }
csr->version++;
/* /*
* subject Name * subject Name
*/ */
...@@ -207,6 +207,13 @@ int mbedtls_x509_csr_parse_der( mbedtls_x509_csr *csr, ...@@ -207,6 +207,13 @@ int mbedtls_x509_csr_parse_der( mbedtls_x509_csr *csr,
/* /*
* attributes [0] Attributes * attributes [0] Attributes
*
* The list of possible attributes is open-ended, though RFC 2985
* (PKCS#9) defines a few in section 5.4. We currently don't support any,
* so we just ignore them. This is a safe thing to do as the worst thing
* that could happen is that we issue a certificate that does not match
* the requester's expectations - this cannot cause a violation of our
* signature policies.
*/ */
if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, if( ( ret = mbedtls_asn1_get_tag( &p, end, &len,
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_CONTEXT_SPECIFIC ) ) != 0 ) MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_CONTEXT_SPECIFIC ) ) != 0 )
...@@ -214,7 +221,6 @@ int mbedtls_x509_csr_parse_der( mbedtls_x509_csr *csr, ...@@ -214,7 +221,6 @@ int mbedtls_x509_csr_parse_der( mbedtls_x509_csr *csr,
mbedtls_x509_csr_free( csr ); mbedtls_x509_csr_free( csr );
return( MBEDTLS_ERR_X509_INVALID_FORMAT + ret ); return( MBEDTLS_ERR_X509_INVALID_FORMAT + ret );
} }
// TODO Parse Attributes / extension requests
p += len; p += len;
...@@ -259,8 +265,8 @@ int mbedtls_x509_csr_parse_der( mbedtls_x509_csr *csr, ...@@ -259,8 +265,8 @@ int mbedtls_x509_csr_parse_der( mbedtls_x509_csr *csr,
*/ */
int mbedtls_x509_csr_parse( mbedtls_x509_csr *csr, const unsigned char *buf, size_t buflen ) int mbedtls_x509_csr_parse( mbedtls_x509_csr *csr, const unsigned char *buf, size_t buflen )
{ {
int ret;
#if defined(MBEDTLS_PEM_PARSE_C) #if defined(MBEDTLS_PEM_PARSE_C)
int ret;
size_t use_len; size_t use_len;
mbedtls_pem_context pem; mbedtls_pem_context pem;
#endif #endif
...@@ -268,14 +274,14 @@ int mbedtls_x509_csr_parse( mbedtls_x509_csr *csr, const unsigned char *buf, siz ...@@ -268,14 +274,14 @@ int mbedtls_x509_csr_parse( mbedtls_x509_csr *csr, const unsigned char *buf, siz
/* /*
* Check for valid input * Check for valid input
*/ */
if( csr == NULL || buf == NULL ) if( csr == NULL || buf == NULL || buflen == 0 )
return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); return( MBEDTLS_ERR_X509_BAD_INPUT_DATA );
#if defined(MBEDTLS_PEM_PARSE_C) #if defined(MBEDTLS_PEM_PARSE_C)
mbedtls_pem_init( &pem ); mbedtls_pem_init( &pem );
/* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */ /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */
if( buflen == 0 || buf[buflen - 1] != '\0' ) if( buf[buflen - 1] != '\0' )
ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT; ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT;
else else
ret = mbedtls_pem_read_buffer( &pem, ret = mbedtls_pem_read_buffer( &pem,
......
...@@ -51,7 +51,7 @@ static void mbedtls_zeroize( void *v, size_t n ) { ...@@ -51,7 +51,7 @@ static void mbedtls_zeroize( void *v, size_t n ) {
void mbedtls_x509write_crt_init( mbedtls_x509write_cert *ctx ) void mbedtls_x509write_crt_init( mbedtls_x509write_cert *ctx )
{ {
memset( ctx, 0, sizeof(mbedtls_x509write_cert) ); memset( ctx, 0, sizeof( mbedtls_x509write_cert ) );
mbedtls_mpi_init( &ctx->serial ); mbedtls_mpi_init( &ctx->serial );
ctx->version = MBEDTLS_X509_CRT_VERSION_3; ctx->version = MBEDTLS_X509_CRT_VERSION_3;
...@@ -65,7 +65,7 @@ void mbedtls_x509write_crt_free( mbedtls_x509write_cert *ctx ) ...@@ -65,7 +65,7 @@ void mbedtls_x509write_crt_free( mbedtls_x509write_cert *ctx )
mbedtls_asn1_free_named_data_list( &ctx->issuer ); mbedtls_asn1_free_named_data_list( &ctx->issuer );
mbedtls_asn1_free_named_data_list( &ctx->extensions ); mbedtls_asn1_free_named_data_list( &ctx->extensions );
mbedtls_zeroize( ctx, sizeof(mbedtls_x509write_cert) ); mbedtls_zeroize( ctx, sizeof( mbedtls_x509write_cert ) );
} }
void mbedtls_x509write_crt_set_version( mbedtls_x509write_cert *ctx, int version ) void mbedtls_x509write_crt_set_version( mbedtls_x509write_cert *ctx, int version )
...@@ -177,8 +177,11 @@ int mbedtls_x509write_crt_set_subject_key_identifier( mbedtls_x509write_cert *ct ...@@ -177,8 +177,11 @@ int mbedtls_x509write_crt_set_subject_key_identifier( mbedtls_x509write_cert *ct
memset( buf, 0, sizeof(buf) ); memset( buf, 0, sizeof(buf) );
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_pk_write_pubkey( &c, buf, ctx->subject_key ) ); MBEDTLS_ASN1_CHK_ADD( len, mbedtls_pk_write_pubkey( &c, buf, ctx->subject_key ) );
mbedtls_sha1( buf + sizeof(buf) - len, len, buf + sizeof(buf) - 20 ); ret = mbedtls_sha1_ret( buf + sizeof( buf ) - len, len,
c = buf + sizeof(buf) - 20; buf + sizeof( buf ) - 20 );
if( ret != 0 )
return( ret );
c = buf + sizeof( buf ) - 20;
len = 20; len = 20;
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, buf, len ) ); MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, buf, len ) );
...@@ -193,14 +196,17 @@ int mbedtls_x509write_crt_set_authority_key_identifier( mbedtls_x509write_cert * ...@@ -193,14 +196,17 @@ int mbedtls_x509write_crt_set_authority_key_identifier( mbedtls_x509write_cert *
{ {
int ret; int ret;
unsigned char buf[MBEDTLS_MPI_MAX_SIZE * 2 + 20]; /* tag, length + 2xMPI */ unsigned char buf[MBEDTLS_MPI_MAX_SIZE * 2 + 20]; /* tag, length + 2xMPI */
unsigned char *c = buf + sizeof(buf); unsigned char *c = buf + sizeof( buf );
size_t len = 0; size_t len = 0;
memset( buf, 0, sizeof(buf) ); memset( buf, 0, sizeof(buf) );
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_pk_write_pubkey( &c, buf, ctx->issuer_key ) ); MBEDTLS_ASN1_CHK_ADD( len, mbedtls_pk_write_pubkey( &c, buf, ctx->issuer_key ) );
mbedtls_sha1( buf + sizeof(buf) - len, len, buf + sizeof(buf) - 20 ); ret = mbedtls_sha1_ret( buf + sizeof( buf ) - len, len,
c = buf + sizeof(buf) - 20; buf + sizeof( buf ) - 20 );
if( ret != 0 )
return( ret );
c = buf + sizeof( buf ) - 20;
len = 20; len = 20;
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, buf, len ) ); MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, buf, len ) );
...@@ -212,7 +218,7 @@ int mbedtls_x509write_crt_set_authority_key_identifier( mbedtls_x509write_cert * ...@@ -212,7 +218,7 @@ int mbedtls_x509write_crt_set_authority_key_identifier( mbedtls_x509write_cert *
return mbedtls_x509write_crt_set_extension( ctx, MBEDTLS_OID_AUTHORITY_KEY_IDENTIFIER, return mbedtls_x509write_crt_set_extension( ctx, MBEDTLS_OID_AUTHORITY_KEY_IDENTIFIER,
MBEDTLS_OID_SIZE( MBEDTLS_OID_AUTHORITY_KEY_IDENTIFIER ), MBEDTLS_OID_SIZE( MBEDTLS_OID_AUTHORITY_KEY_IDENTIFIER ),
0, buf + sizeof(buf) - len, len ); 0, buf + sizeof( buf ) - len, len );
} }
#endif /* MBEDTLS_SHA1_C */ #endif /* MBEDTLS_SHA1_C */
...@@ -264,7 +270,7 @@ int mbedtls_x509write_crt_set_ns_cert_type( mbedtls_x509write_cert *ctx, ...@@ -264,7 +270,7 @@ int mbedtls_x509write_crt_set_ns_cert_type( mbedtls_x509write_cert *ctx,
} }
static int x509_write_time( unsigned char **p, unsigned char *start, static int x509_write_time( unsigned char **p, unsigned char *start,
const char *time, size_t size ) const char *t, size_t size )
{ {
int ret; int ret;
size_t len = 0; size_t len = 0;
...@@ -272,10 +278,10 @@ static int x509_write_time( unsigned char **p, unsigned char *start, ...@@ -272,10 +278,10 @@ static int x509_write_time( unsigned char **p, unsigned char *start,
/* /*
* write MBEDTLS_ASN1_UTC_TIME if year < 2050 (2 bytes shorter) * write MBEDTLS_ASN1_UTC_TIME if year < 2050 (2 bytes shorter)
*/ */
if( time[0] == '2' && time[1] == '0' && time [2] < '5' ) if( t[0] == '2' && t[1] == '0' && t[2] < '5' )
{ {
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_raw_buffer( p, start, MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_raw_buffer( p, start,
(const unsigned char *) time + 2, (const unsigned char *) t + 2,
size - 2 ) ); size - 2 ) );
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) ); MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) );
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_UTC_TIME ) ); MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_UTC_TIME ) );
...@@ -283,7 +289,7 @@ static int x509_write_time( unsigned char **p, unsigned char *start, ...@@ -283,7 +289,7 @@ static int x509_write_time( unsigned char **p, unsigned char *start,
else else
{ {
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_raw_buffer( p, start, MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_raw_buffer( p, start,
(const unsigned char *) time, (const unsigned char *) t,
size ) ); size ) );
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) ); MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) );
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_GENERALIZED_TIME ) ); MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_GENERALIZED_TIME ) );
...@@ -313,9 +319,15 @@ int mbedtls_x509write_crt_der( mbedtls_x509write_cert *ctx, unsigned char *buf, ...@@ -313,9 +319,15 @@ int mbedtls_x509write_crt_der( mbedtls_x509write_cert *ctx, unsigned char *buf,
c = tmp_buf + sizeof( tmp_buf ); c = tmp_buf + sizeof( tmp_buf );
/* Signature algorithm needed in TBS, and later for actual signature */ /* Signature algorithm needed in TBS, and later for actual signature */
pk_alg = mbedtls_pk_get_type( ctx->issuer_key );
if( pk_alg == MBEDTLS_PK_ECKEY ) /* There's no direct way of extracting a signature algorithm
* (represented as an element of mbedtls_pk_type_t) from a PK instance. */
if( mbedtls_pk_can_do( ctx->issuer_key, MBEDTLS_PK_RSA ) )
pk_alg = MBEDTLS_PK_RSA;
else if( mbedtls_pk_can_do( ctx->issuer_key, MBEDTLS_PK_ECDSA ) )
pk_alg = MBEDTLS_PK_ECDSA; pk_alg = MBEDTLS_PK_ECDSA;
else
return( MBEDTLS_ERR_X509_INVALID_ALG );
if( ( ret = mbedtls_oid_get_oid_by_sig_alg( pk_alg, ctx->md_alg, if( ( ret = mbedtls_oid_get_oid_by_sig_alg( pk_alg, ctx->md_alg,
&sig_oid, &sig_oid_len ) ) != 0 ) &sig_oid, &sig_oid_len ) ) != 0 )
...@@ -326,6 +338,10 @@ int mbedtls_x509write_crt_der( mbedtls_x509write_cert *ctx, unsigned char *buf, ...@@ -326,6 +338,10 @@ int mbedtls_x509write_crt_der( mbedtls_x509write_cert *ctx, unsigned char *buf,
/* /*
* Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension * Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension
*/ */
/* Only for v3 */
if( ctx->version == MBEDTLS_X509_CRT_VERSION_3 )
{
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_x509_write_extensions( &c, tmp_buf, ctx->extensions ) ); MBEDTLS_ASN1_CHK_ADD( len, mbedtls_x509_write_extensions( &c, tmp_buf, ctx->extensions ) );
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, tmp_buf, len ) ); MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, tmp_buf, len ) );
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, tmp_buf, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, tmp_buf, MBEDTLS_ASN1_CONSTRUCTED |
...@@ -333,6 +349,7 @@ int mbedtls_x509write_crt_der( mbedtls_x509write_cert *ctx, unsigned char *buf, ...@@ -333,6 +349,7 @@ int mbedtls_x509write_crt_der( mbedtls_x509write_cert *ctx, unsigned char *buf,
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, tmp_buf, len ) ); MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, tmp_buf, len ) );
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, tmp_buf, MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, tmp_buf, MBEDTLS_ASN1_CONTEXT_SPECIFIC |
MBEDTLS_ASN1_CONSTRUCTED | 3 ) ); MBEDTLS_ASN1_CONSTRUCTED | 3 ) );
}
/* /*
* SubjectPublicKeyInfo * SubjectPublicKeyInfo
...@@ -384,12 +401,17 @@ int mbedtls_x509write_crt_der( mbedtls_x509write_cert *ctx, unsigned char *buf, ...@@ -384,12 +401,17 @@ int mbedtls_x509write_crt_der( mbedtls_x509write_cert *ctx, unsigned char *buf,
/* /*
* Version ::= INTEGER { v1(0), v2(1), v3(2) } * Version ::= INTEGER { v1(0), v2(1), v3(2) }
*/ */
/* Can be omitted for v1 */
if( ctx->version != MBEDTLS_X509_CRT_VERSION_1 )
{
sub_len = 0; sub_len = 0;
MBEDTLS_ASN1_CHK_ADD( sub_len, mbedtls_asn1_write_int( &c, tmp_buf, ctx->version ) ); MBEDTLS_ASN1_CHK_ADD( sub_len, mbedtls_asn1_write_int( &c, tmp_buf, ctx->version ) );
len += sub_len; len += sub_len;
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, tmp_buf, sub_len ) ); MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, tmp_buf, sub_len ) );
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, tmp_buf, MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, tmp_buf, MBEDTLS_ASN1_CONTEXT_SPECIFIC |
MBEDTLS_ASN1_CONSTRUCTED | 0 ) ); MBEDTLS_ASN1_CONSTRUCTED | 0 ) );
}
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, tmp_buf, len ) ); MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, tmp_buf, len ) );
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, tmp_buf, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, tmp_buf, MBEDTLS_ASN1_CONSTRUCTED |
...@@ -398,7 +420,11 @@ int mbedtls_x509write_crt_der( mbedtls_x509write_cert *ctx, unsigned char *buf, ...@@ -398,7 +420,11 @@ int mbedtls_x509write_crt_der( mbedtls_x509write_cert *ctx, unsigned char *buf,
/* /*
* Make signature * Make signature
*/ */
mbedtls_md( mbedtls_md_info_from_type( ctx->md_alg ), c, len, hash ); if( ( ret = mbedtls_md( mbedtls_md_info_from_type( ctx->md_alg ), c,
len, hash ) ) != 0 )
{
return( ret );
}
if( ( ret = mbedtls_pk_sign( ctx->issuer_key, ctx->md_alg, hash, 0, sig, &sig_len, if( ( ret = mbedtls_pk_sign( ctx->issuer_key, ctx->md_alg, hash, 0, sig, &sig_len,
f_rng, p_rng ) ) != 0 ) f_rng, p_rng ) ) != 0 )
...@@ -413,6 +439,9 @@ int mbedtls_x509write_crt_der( mbedtls_x509write_cert *ctx, unsigned char *buf, ...@@ -413,6 +439,9 @@ int mbedtls_x509write_crt_der( mbedtls_x509write_cert *ctx, unsigned char *buf,
MBEDTLS_ASN1_CHK_ADD( sig_and_oid_len, mbedtls_x509_write_sig( &c2, buf, MBEDTLS_ASN1_CHK_ADD( sig_and_oid_len, mbedtls_x509_write_sig( &c2, buf,
sig_oid, sig_oid_len, sig, sig_len ) ); sig_oid, sig_oid_len, sig, sig_len ) );
if( len > (size_t)( c2 - buf ) )
return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL );
c2 -= len; c2 -= len;
memcpy( c2, c, len ); memcpy( c2, c, len );
......
...@@ -50,7 +50,7 @@ static void mbedtls_zeroize( void *v, size_t n ) { ...@@ -50,7 +50,7 @@ static void mbedtls_zeroize( void *v, size_t n ) {
void mbedtls_x509write_csr_init( mbedtls_x509write_csr *ctx ) void mbedtls_x509write_csr_init( mbedtls_x509write_csr *ctx )
{ {
memset( ctx, 0, sizeof(mbedtls_x509write_csr) ); memset( ctx, 0, sizeof( mbedtls_x509write_csr ) );
} }
void mbedtls_x509write_csr_free( mbedtls_x509write_csr *ctx ) void mbedtls_x509write_csr_free( mbedtls_x509write_csr *ctx )
...@@ -58,7 +58,7 @@ void mbedtls_x509write_csr_free( mbedtls_x509write_csr *ctx ) ...@@ -58,7 +58,7 @@ void mbedtls_x509write_csr_free( mbedtls_x509write_csr *ctx )
mbedtls_asn1_free_named_data_list( &ctx->subject ); mbedtls_asn1_free_named_data_list( &ctx->subject );
mbedtls_asn1_free_named_data_list( &ctx->extensions ); mbedtls_asn1_free_named_data_list( &ctx->extensions );
mbedtls_zeroize( ctx, sizeof(mbedtls_x509write_csr) ); mbedtls_zeroize( ctx, sizeof( mbedtls_x509write_csr ) );
} }
void mbedtls_x509write_csr_set_md_alg( mbedtls_x509write_csr *ctx, mbedtls_md_type_t md_alg ) void mbedtls_x509write_csr_set_md_alg( mbedtls_x509write_csr *ctx, mbedtls_md_type_t md_alg )
...@@ -194,13 +194,20 @@ int mbedtls_x509write_csr_der( mbedtls_x509write_csr *ctx, unsigned char *buf, s ...@@ -194,13 +194,20 @@ int mbedtls_x509write_csr_der( mbedtls_x509write_csr *ctx, unsigned char *buf, s
*/ */
mbedtls_md( mbedtls_md_info_from_type( ctx->md_alg ), c, len, hash ); mbedtls_md( mbedtls_md_info_from_type( ctx->md_alg ), c, len, hash );
pk_alg = mbedtls_pk_get_type( ctx->key ); if( ( ret = mbedtls_pk_sign( ctx->key, ctx->md_alg, hash, 0, sig, &sig_len,
if( pk_alg == MBEDTLS_PK_ECKEY ) f_rng, p_rng ) ) != 0 )
{
return( ret );
}
if( mbedtls_pk_can_do( ctx->key, MBEDTLS_PK_RSA ) )
pk_alg = MBEDTLS_PK_RSA;
else if( mbedtls_pk_can_do( ctx->key, MBEDTLS_PK_ECDSA ) )
pk_alg = MBEDTLS_PK_ECDSA; pk_alg = MBEDTLS_PK_ECDSA;
else
return( MBEDTLS_ERR_X509_INVALID_ALG );
if( ( ret = mbedtls_pk_sign( ctx->key, ctx->md_alg, hash, 0, sig, &sig_len, if( ( ret = mbedtls_oid_get_oid_by_sig_alg( pk_alg, ctx->md_alg,
f_rng, p_rng ) ) != 0 ||
( ret = mbedtls_oid_get_oid_by_sig_alg( pk_alg, ctx->md_alg,
&sig_oid, &sig_oid_len ) ) != 0 ) &sig_oid, &sig_oid_len ) ) != 0 )
{ {
return( ret ); return( ret );
...@@ -213,6 +220,9 @@ int mbedtls_x509write_csr_der( mbedtls_x509write_csr *ctx, unsigned char *buf, s ...@@ -213,6 +220,9 @@ int mbedtls_x509write_csr_der( mbedtls_x509write_csr *ctx, unsigned char *buf, s
MBEDTLS_ASN1_CHK_ADD( sig_and_oid_len, mbedtls_x509_write_sig( &c2, buf, MBEDTLS_ASN1_CHK_ADD( sig_and_oid_len, mbedtls_x509_write_sig( &c2, buf,
sig_oid, sig_oid_len, sig, sig_len ) ); sig_oid, sig_oid_len, sig, sig_len ) );
if( len > (size_t)( c2 - buf ) )
return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL );
c2 -= len; c2 -= len;
memcpy( c2, c, len ); memcpy( c2, c, len );
......
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
#if defined(MBEDTLS_NET_C) #if defined(MBEDTLS_NET_C)
#include "mbedtls/net.h" #include "mbedtls/net_sockets.h"
#include <string.h> #include <string.h>
// //
......
...@@ -56,6 +56,7 @@ INCLUDES += -I ../http ...@@ -56,6 +56,7 @@ INCLUDES += -I ../http
INCLUDES += -I ../sjson INCLUDES += -I ../sjson
INCLUDES += -I ../websocket INCLUDES += -I ../websocket
INCLUDES += -I ../pm INCLUDES += -I ../pm
INCLUDES += -I ../sqlite3
PDIR := ../$(PDIR) PDIR := ../$(PDIR)
sinclude $(PDIR)Makefile sinclude $(PDIR)Makefile
...@@ -8,6 +8,14 @@ ...@@ -8,6 +8,14 @@
#include "lauxlib.h" #include "lauxlib.h"
#include "platform.h" #include "platform.h"
#include "osapi.h" #include "osapi.h"
#include "c_stdlib.h"
//***************************************************************************
// CHIP
//***************************************************************************
#define ADS1115_ADS1015 ( 15)
#define ADS1115_ADS1115 (115)
//*************************************************************************** //***************************************************************************
// I2C ADDRESS DEFINITON // I2C ADDRESS DEFINITON
...@@ -17,6 +25,7 @@ ...@@ -17,6 +25,7 @@
#define ADS1115_I2C_ADDR_VDD (0x49) #define ADS1115_I2C_ADDR_VDD (0x49)
#define ADS1115_I2C_ADDR_SDA (0x4A) #define ADS1115_I2C_ADDR_SDA (0x4A)
#define ADS1115_I2C_ADDR_SCL (0x4B) #define ADS1115_I2C_ADDR_SCL (0x4B)
#define IS_I2C_ADDR_VALID(addr) (((addr) & 0xFC) == 0x48)
//*************************************************************************** //***************************************************************************
// POINTER REGISTER // POINTER REGISTER
...@@ -47,6 +56,7 @@ ...@@ -47,6 +56,7 @@
#define ADS1115_MUX_SINGLE_1 (0x5000) // Single-ended AIN1 #define ADS1115_MUX_SINGLE_1 (0x5000) // Single-ended AIN1
#define ADS1115_MUX_SINGLE_2 (0x6000) // Single-ended AIN2 #define ADS1115_MUX_SINGLE_2 (0x6000) // Single-ended AIN2
#define ADS1115_MUX_SINGLE_3 (0x7000) // Single-ended AIN3 #define ADS1115_MUX_SINGLE_3 (0x7000) // Single-ended AIN3
#define IS_CHANNEL_VALID(channel) (((channel) & 0x8FFF) == 0)
#define ADS1115_PGA_MASK (0x0E00) #define ADS1115_PGA_MASK (0x0E00)
#define ADS1115_PGA_6_144V (0x0000) // +/-6.144V range = Gain 2/3 #define ADS1115_PGA_6_144V (0x0000) // +/-6.144V range = Gain 2/3
...@@ -61,14 +71,19 @@ ...@@ -61,14 +71,19 @@
#define ADS1115_MODE_SINGLE (0x0100) // Power-down single-shot mode (default) #define ADS1115_MODE_SINGLE (0x0100) // Power-down single-shot mode (default)
#define ADS1115_DR_MASK (0x00E0) #define ADS1115_DR_MASK (0x00E0)
#define ADS1115_DR_8SPS (0x0000) // 8 samples per second #define ADS1115_DR_8SPS ( 8)
#define ADS1115_DR_16SPS (0x0020) // 16 samples per second #define ADS1115_DR_16SPS ( 16)
#define ADS1115_DR_32SPS (0x0040) // 32 samples per second #define ADS1115_DR_32SPS ( 32)
#define ADS1115_DR_64SPS (0x0060) // 64 samples per second #define ADS1115_DR_64SPS ( 64)
#define ADS1115_DR_128SPS (0x0080) // 128 samples per second (default) #define ADS1115_DR_128SPS ( 128)
#define ADS1115_DR_250SPS (0x00A0) // 250 samples per second #define ADS1115_DR_250SPS ( 250)
#define ADS1115_DR_475SPS (0x00C0) // 475 samples per second #define ADS1115_DR_475SPS ( 475)
#define ADS1115_DR_860SPS (0x00E0) // 860 samples per second #define ADS1115_DR_490SPS ( 490)
#define ADS1115_DR_860SPS ( 860)
#define ADS1115_DR_920SPS ( 920)
#define ADS1115_DR_1600SPS (1600)
#define ADS1115_DR_2400SPS (2400)
#define ADS1115_DR_3300SPS (3300)
#define ADS1115_CMODE_MASK (0x0010) #define ADS1115_CMODE_MASK (0x0010)
#define ADS1115_CMODE_TRAD (0x0000) // Traditional comparator with hysteresis (default) #define ADS1115_CMODE_TRAD (0x0000) // Traditional comparator with hysteresis (default)
...@@ -88,44 +103,53 @@ ...@@ -88,44 +103,53 @@
#define ADS1115_CQUE_4CONV (0x0002) // Assert ALERT/RDY after four conversions #define ADS1115_CQUE_4CONV (0x0002) // Assert ALERT/RDY after four conversions
#define ADS1115_CQUE_NONE (0x0003) // Disable the comparator and put ALERT/RDY in high state (default) #define ADS1115_CQUE_NONE (0x0003) // Disable the comparator and put ALERT/RDY in high state (default)
#define ADS1115_DEFAULT_CONFIG_REG (0x8583) // Config register value after reset
// #define ADS1115_INCLUDE_TEST_FUNCTION
//*************************************************************************** //***************************************************************************
static const uint8_t ads1115_i2c_id = 0; static const uint8_t ads1115_i2c_id = 0;
static const uint8_t general_i2c_addr = 0x00; static const uint8_t general_i2c_addr = 0x00;
static const uint8_t ads1115_i2c_reset = 0x06; static const uint8_t ads1115_i2c_reset = 0x06;
static uint8_t ads1115_i2c_addr = ADS1115_I2C_ADDR_GND; static const char metatable_name[] = "ads1115.device";
static uint16_t ads1115_os = ADS1115_OS_SINGLE; static const char unexpected_value[] = "unexpected value";
static uint16_t ads1115_gain = ADS1115_PGA_6_144V;
static uint16_t ads1115_samples = ADS1115_DR_128SPS; typedef struct {
static uint16_t ads1115_channel = ADS1115_MUX_SINGLE_0; uint8_t i2c_addr;
static uint16_t ads1115_comp = ADS1115_CQUE_NONE; uint8_t chip_id;
static uint16_t ads1115_mode = ADS1115_MODE_SINGLE; uint16_t gain;
static uint16_t ads1115_threshold_low = 0x8000; uint16_t samples_value; // sample per second
static uint16_t ads1115_threshold_hi = 0x7FFF; uint16_t samples; // register value
static uint16_t ads1115_config = 0x8583; uint16_t comp;
static uint16_t ads1115_conversion = 0; uint16_t mode;
static double ads1115_volt = 0; uint16_t threshold_low;
os_timer_t ads1115_timer; // timer for conversion delay uint16_t threshold_hi;
int ads1115_timer_ref; // callback when readout is ready uint16_t config;
int timer_ref;
static int ads1115_lua_readoutdone(void); os_timer_t timer;
} ads_ctrl_ud_t;
static uint8_t write_reg(uint8_t reg, uint16_t config) {
static int ads1115_lua_readoutdone(void * param);
static int ads1115_lua_register(lua_State *L, uint8_t chip_id);
static uint8_t write_reg(uint8_t ads_addr, uint8_t reg, uint16_t config) {
platform_i2c_send_start(ads1115_i2c_id); platform_i2c_send_start(ads1115_i2c_id);
platform_i2c_send_address(ads1115_i2c_id, ads1115_i2c_addr, PLATFORM_I2C_DIRECTION_TRANSMITTER); platform_i2c_send_address(ads1115_i2c_id, ads_addr, PLATFORM_I2C_DIRECTION_TRANSMITTER);
platform_i2c_send_byte(ads1115_i2c_id, reg); platform_i2c_send_byte(ads1115_i2c_id, reg);
platform_i2c_send_byte(ads1115_i2c_id, (uint8_t)(config >> 8)); platform_i2c_send_byte(ads1115_i2c_id, (uint8_t)(config >> 8));
platform_i2c_send_byte(ads1115_i2c_id, (uint8_t)(config & 0xFF)); platform_i2c_send_byte(ads1115_i2c_id, (uint8_t)(config & 0xFF));
platform_i2c_send_stop(ads1115_i2c_id); platform_i2c_send_stop(ads1115_i2c_id);
} }
static uint16_t read_reg(uint8_t reg) { static uint16_t read_reg(uint8_t ads_addr, uint8_t reg) {
platform_i2c_send_start(ads1115_i2c_id); platform_i2c_send_start(ads1115_i2c_id);
platform_i2c_send_address(ads1115_i2c_id, ads1115_i2c_addr, PLATFORM_I2C_DIRECTION_TRANSMITTER); platform_i2c_send_address(ads1115_i2c_id, ads_addr, PLATFORM_I2C_DIRECTION_TRANSMITTER);
platform_i2c_send_byte(ads1115_i2c_id, reg); platform_i2c_send_byte(ads1115_i2c_id, reg);
platform_i2c_send_stop(ads1115_i2c_id); platform_i2c_send_stop(ads1115_i2c_id);
platform_i2c_send_start(ads1115_i2c_id); platform_i2c_send_start(ads1115_i2c_id);
platform_i2c_send_address(ads1115_i2c_id, ads1115_i2c_addr, PLATFORM_I2C_DIRECTION_RECEIVER); platform_i2c_send_address(ads1115_i2c_id, ads_addr, PLATFORM_I2C_DIRECTION_RECEIVER);
uint16_t buf = (platform_i2c_recv_byte(ads1115_i2c_id, 1) << 8); uint16_t buf = (platform_i2c_recv_byte(ads1115_i2c_id, 1) << 8);
buf += platform_i2c_recv_byte(ads1115_i2c_id, 0); buf += platform_i2c_recv_byte(ads1115_i2c_id, 0);
platform_i2c_send_stop(ads1115_i2c_id); platform_i2c_send_stop(ads1115_i2c_id);
...@@ -133,11 +157,12 @@ static uint16_t read_reg(uint8_t reg) { ...@@ -133,11 +157,12 @@ static uint16_t read_reg(uint8_t reg) {
} }
// convert ADC value to voltage corresponding to PGA settings // convert ADC value to voltage corresponding to PGA settings
static double get_volt(uint16_t value) { // returned voltage is in milivolts
static double get_mvolt(uint16_t gain, uint16_t value) {
double volt = 0; double volt = 0;
switch (ads1115_gain) { switch (gain) {
case (ADS1115_PGA_6_144V): case (ADS1115_PGA_6_144V):
volt = (int16_t)value * 0.1875; volt = (int16_t)value * 0.1875;
break; break;
...@@ -161,253 +186,356 @@ static double get_volt(uint16_t value) { ...@@ -161,253 +186,356 @@ static double get_volt(uint16_t value) {
return volt; return volt;
} }
// convert threshold in volt to ADC value corresponding to PGA settings // validates and convert threshold in volt to ADC value corresponding to PGA settings
static uint8_t get_value(int16_t *volt) { // returns true if valid
static uint8_t get_value(uint16_t gain, uint16_t channel, int16_t *volt) {
switch (ads1115_gain) { switch (gain) {
case (ADS1115_PGA_6_144V): case (ADS1115_PGA_6_144V):
if ((*volt >= 6144) || (*volt < -6144) || ((*volt < 0) && (ads1115_channel >> 14))) return 1; if ((*volt >= 6144) || (*volt < -6144) || ((*volt < 0) && (channel >> 14))) return 0;
*volt = *volt / 0.1875; *volt = *volt / 0.1875;
break; break;
case (ADS1115_PGA_4_096V): case (ADS1115_PGA_4_096V):
if ((*volt >= 4096) || (*volt < -4096) || ((*volt < 0) && (ads1115_channel >> 14))) return 1; if ((*volt >= 4096) || (*volt < -4096) || ((*volt < 0) && (channel >> 14))) return 0;
*volt = *volt / 0.125; *volt = *volt / 0.125;
break; break;
case (ADS1115_PGA_2_048V): case (ADS1115_PGA_2_048V):
if ((*volt >= 2048) || (*volt < -2048) || ((*volt < 0) && (ads1115_channel >> 14))) return 1; if ((*volt >= 2048) || (*volt < -2048) || ((*volt < 0) && (channel >> 14))) return 0;
*volt = *volt / 0.0625; *volt = *volt / 0.0625;
break; break;
case (ADS1115_PGA_1_024V): case (ADS1115_PGA_1_024V):
if ((*volt >= 1024) || (*volt < -1024) || ((*volt < 0) && (ads1115_channel >> 14))) return 1; if ((*volt >= 1024) || (*volt < -1024) || ((*volt < 0) && (channel >> 14))) return 0;
*volt = *volt / 0.03125; *volt = *volt / 0.03125;
break; break;
case (ADS1115_PGA_0_512V): case (ADS1115_PGA_0_512V):
if ((*volt >= 512) || (*volt < -512) || ((*volt < 0) && (ads1115_channel >> 14))) return 1; if ((*volt >= 512) || (*volt < -512) || ((*volt < 0) && (channel >> 14))) return 0;
*volt = *volt / 0.015625; *volt = *volt / 0.015625;
break; break;
case (ADS1115_PGA_0_256V): case (ADS1115_PGA_0_256V):
if ((*volt >= 256) || (*volt < -256) || ((*volt < 0) && (ads1115_channel >> 14))) return 1; if ((*volt >= 256) || (*volt < -256) || ((*volt < 0) && (channel >> 14))) return 0;
*volt = *volt / 0.0078125; *volt = *volt / 0.0078125;
break; break;
} }
return 1;
return 0;
} }
// Initializes ADC
// Lua: ads11115.setup(ADDRESS)
static int ads1115_lua_setup(lua_State *L) {
// check variables
if (!lua_isnumber(L, 1)) {
return luaL_error(L, "wrong arg range");
}
ads1115_i2c_addr = luaL_checkinteger(L, 1);
if (!((ads1115_i2c_addr == ADS1115_I2C_ADDR_GND) || (ads1115_i2c_addr == ADS1115_I2C_ADDR_VDD) || (ads1115_i2c_addr == ADS1115_I2C_ADDR_SDA) || (ads1115_i2c_addr == ADS1115_I2C_ADDR_SCL))) {
return luaL_error(L, "Invalid argument: adddress");
}
// Reset of all devices
// Lua: ads1115.reset()
static int ads1115_lua_reset(lua_State *L) {
platform_i2c_send_start(ads1115_i2c_id); platform_i2c_send_start(ads1115_i2c_id);
platform_i2c_send_address(ads1115_i2c_id, general_i2c_addr, PLATFORM_I2C_DIRECTION_TRANSMITTER); platform_i2c_send_address(ads1115_i2c_id, general_i2c_addr, PLATFORM_I2C_DIRECTION_TRANSMITTER);
platform_i2c_send_byte(ads1115_i2c_id, ads1115_i2c_reset); platform_i2c_send_byte(ads1115_i2c_id, ads1115_i2c_reset);
platform_i2c_send_stop(ads1115_i2c_id); platform_i2c_send_stop(ads1115_i2c_id);
// check for device on i2c bus
if (read_reg(ADS1115_POINTER_CONFIG) != 0x8583) {
return luaL_error(L, "found no device");
}
return 0; return 0;
} }
// Change ADC settings // Register an ADS device
// Lua: ads1115.setting(GAIN,SAMPLES,CHANNEL,MODE[,CONVERSION_RDY][,COMPARATOR,THRESHOLD_LOW,THRESHOLD_HI]) // Lua: ads1115.ADS1115(I2C_ID, ADDRESS)
static int ads1115_lua_setting(lua_State *L) { static int ads1115_lua_register_1115(lua_State *L) {
return ads1115_lua_register(L, ADS1115_ADS1115);
}
// check variables static int ads1115_lua_register_1015(lua_State *L) {
if (!lua_isnumber(L, 1) || !lua_isnumber(L, 2) || !lua_isnumber(L, 3) || !lua_isnumber(L, 4)) { return ads1115_lua_register(L, ADS1115_ADS1015);
return luaL_error(L, "wrong arg range"); }
}
ads1115_gain = luaL_checkinteger(L, 1); static int ads1115_lua_register(lua_State *L, uint8_t chip_id) {
if (!((ads1115_gain == ADS1115_PGA_6_144V) || (ads1115_gain == ADS1115_PGA_4_096V) || (ads1115_gain == ADS1115_PGA_2_048V) || (ads1115_gain == ADS1115_PGA_1_024V) || (ads1115_gain == ADS1115_PGA_0_512V) || (ads1115_gain == ADS1115_PGA_0_256V))) { uint8_t i2c_id = luaL_checkinteger(L, 1);
return luaL_error(L, "Invalid argument: gain"); luaL_argcheck(L, 0 == i2c_id, 1, "i2c_id must be 0");
uint8_t i2c_addr = luaL_checkinteger(L, 2);
luaL_argcheck(L, IS_I2C_ADDR_VALID(i2c_addr), 2, unexpected_value);
uint16_t config_read = read_reg(i2c_addr, ADS1115_POINTER_CONFIG);
if (config_read == 0xFFFF) {
return luaL_error(L, "found no device");
} }
if (config_read != ADS1115_DEFAULT_CONFIG_REG) {
ads1115_samples = luaL_checkinteger(L, 2); return luaL_error(L, "unexpected config value (%p) please reset device before calling this function", config_read);
if (!((ads1115_samples == ADS1115_DR_8SPS) || (ads1115_samples == ADS1115_DR_16SPS) || (ads1115_samples == ADS1115_DR_32SPS) || (ads1115_samples == ADS1115_DR_64SPS) || (ads1115_samples == ADS1115_DR_128SPS) || (ads1115_samples == ADS1115_DR_250SPS) || (ads1115_samples == ADS1115_DR_475SPS) || (ads1115_samples == ADS1115_DR_860SPS))) {
return luaL_error(L, "Invalid argument: samples");
} }
ads_ctrl_ud_t *ads_ctrl = (ads_ctrl_ud_t *)lua_newuserdata(L, sizeof(ads_ctrl_ud_t));
ads1115_channel = luaL_checkinteger(L, 3); if (NULL == ads_ctrl) {
if (!((ads1115_channel == ADS1115_MUX_SINGLE_0) || (ads1115_channel == ADS1115_MUX_SINGLE_1) || (ads1115_channel == ADS1115_MUX_SINGLE_2) || (ads1115_channel == ADS1115_MUX_SINGLE_3) || (ads1115_channel == ADS1115_MUX_DIFF_0_1) || (ads1115_channel == ADS1115_MUX_DIFF_0_3) || (ads1115_channel == ADS1115_MUX_DIFF_1_3) || (ads1115_channel == ADS1115_MUX_DIFF_2_3))) { return luaL_error(L, "ads1115 malloc: out of memory");
return luaL_error(L, "Invalid argument: channel");
}
ads1115_mode = luaL_checkinteger(L, 4);
if (!((ads1115_mode == ADS1115_MODE_SINGLE) || (ads1115_mode == ADS1115_MODE_CONTIN))) {
return luaL_error(L, "Invalid argument: mode");
} }
luaL_getmetatable(L, metatable_name);
lua_setmetatable(L, -2);
ads_ctrl->chip_id = chip_id;
ads_ctrl->i2c_addr = i2c_addr;
ads_ctrl->gain = ADS1115_PGA_6_144V;
ads_ctrl->samples = ADS1115_DR_128SPS;
ads_ctrl->samples_value = chip_id == ADS1115_ADS1115 ? 128 : 1600;
ads_ctrl->comp = ADS1115_CQUE_NONE;
ads_ctrl->mode = ADS1115_MODE_SINGLE;
ads_ctrl->threshold_low = 0x8000;
ads_ctrl->threshold_hi = 0x7FFF;
ads_ctrl->config = ADS1115_DEFAULT_CONFIG_REG;
ads_ctrl->timer_ref = LUA_NOREF;
return 1;
}
if (ads1115_mode == ADS1115_MODE_SINGLE) { // Change the ADC device settings
ads1115_os = ADS1115_OS_SINGLE; // Lua: ads1115.device:settings(GAIN,SAMPLES,CHANNEL,MODE[,CONVERSION_RDY][,COMPARATOR,THRESHOLD_LOW,THRESHOLD_HI[,COMP_MODE])
} else { static int ads1115_lua_setting(lua_State *L) {
ads1115_os = ADS1115_OS_NON; int argc = lua_gettop(L);
if (argc != 5 && argc != 6 && argc != 8 && argc != 9) { // user data counts
luaL_error(L, "invalid number of arguments to 'setting'");
} }
ads_ctrl_ud_t *ads_ctrl = luaL_checkudata(L, 1, metatable_name);
ads1115_comp = ADS1115_CQUE_NONE; // gain
uint16_t gain = luaL_checkinteger(L, 2);
// Parse optional parameters luaL_argcheck(L, (gain == ADS1115_PGA_6_144V) || (gain == ADS1115_PGA_4_096V) || (gain == ADS1115_PGA_2_048V) ||
if (lua_isnumber(L, 5) && !(lua_isnumber(L, 6) || lua_isnumber(L, 7))) { (gain == ADS1115_PGA_1_024V) || (gain == ADS1115_PGA_0_512V) || (gain == ADS1115_PGA_0_256V),
2, unexpected_value);
// conversion ready mode ads_ctrl->gain = gain;
ads1115_comp = luaL_checkinteger(L, 5); // samples
if (!((ads1115_comp == ADS1115_CQUE_1CONV) || (ads1115_comp == ADS1115_CQUE_2CONV) || (ads1115_comp == ADS1115_CQUE_4CONV))) { uint16_t samples_value = luaL_checkinteger(L, 3);
return luaL_error(L, "Invalid argument: conversion ready mode"); uint16_t samples = 0;
if (ads_ctrl->chip_id == ADS1115_ADS1115) {
switch(samples_value) {
case ADS1115_DR_8SPS:
samples = 0;
break;
case ADS1115_DR_16SPS:
samples = 0x20;
break;
case ADS1115_DR_32SPS:
samples = 0x40;
break;
case ADS1115_DR_64SPS:
samples = 0x60;
break;
case ADS1115_DR_128SPS: // default
samples = 0x80;
break;
case ADS1115_DR_250SPS:
samples = 0xA0;
break;
case ADS1115_DR_475SPS:
samples = 0xC0;
break;
case ADS1115_DR_860SPS:
samples = 0xE0;
break;
default:
luaL_argerror(L, 3, unexpected_value);
} }
} else { // ADS1115_ADS1015
ads1115_threshold_low = 0x7FFF; switch(samples_value) {
ads1115_threshold_hi = 0x8000; case ADS1115_DR_128SPS:
samples = 0;
write_reg(ADS1115_POINTER_THRESH_LOW, ads1115_threshold_low); break;
write_reg(ADS1115_POINTER_THRESH_HI, ads1115_threshold_hi); case ADS1115_DR_250SPS:
samples = 0x20;
} else if (lua_isnumber(L, 5) && lua_isnumber(L, 6) && lua_isnumber(L, 7)) { break;
case ADS1115_DR_490SPS:
// comparator mode samples = 0x40;
ads1115_comp = luaL_checkinteger(L, 5); break;
if (!((ads1115_comp == ADS1115_CQUE_1CONV) || (ads1115_comp == ADS1115_CQUE_2CONV) || (ads1115_comp == ADS1115_CQUE_4CONV))) { case ADS1115_DR_920SPS:
return luaL_error(L, "Invalid argument: comparator mode"); samples = 0x60;
break;
case ADS1115_DR_1600SPS: // default
samples = 0x80;
break;
case ADS1115_DR_2400SPS:
samples = 0xA0;
break;
case ADS1115_DR_3300SPS:
samples = 0xC0;
break;
default:
luaL_argerror(L, 3, unexpected_value);
} }
ads1115_threshold_low = luaL_checkinteger(L, 5);
ads1115_threshold_hi = luaL_checkinteger(L, 6);
if ((int16_t)ads1115_threshold_low > (int16_t)ads1115_threshold_hi) {
return luaL_error(L, "Invalid argument: threshold_low > threshold_hi");
} }
ads_ctrl->samples = samples;
if (get_value(&ads1115_threshold_low)) { ads_ctrl->samples_value = samples_value;
return luaL_error(L, "Invalid argument: threshold_low"); // channel
uint16_t channel = luaL_checkinteger(L, 4);
luaL_argcheck(L, IS_CHANNEL_VALID(channel), 4, unexpected_value);
// mode
uint16_t mode = luaL_checkinteger(L, 5);
luaL_argcheck(L, (mode == ADS1115_MODE_SINGLE) || (mode == ADS1115_MODE_CONTIN), 5, unexpected_value);
ads_ctrl->mode = mode;
uint16_t os = mode == ADS1115_MODE_SINGLE ? ADS1115_OS_SINGLE : ADS1115_OS_NON;
uint16_t comp = ADS1115_CQUE_NONE;
// Parse optional parameters
if (argc > 5) {
// comparator or conversion count
comp = luaL_checkinteger(L, 6);
luaL_argcheck(L, (comp == ADS1115_CQUE_1CONV) || (comp == ADS1115_CQUE_2CONV) || (comp == ADS1115_CQUE_4CONV),
6, unexpected_value);
uint16_t threshold_low = 0x7FFF;
uint16_t threshold_hi = 0x8000;
if (argc > 6) {
// comparator thresholds
threshold_low = luaL_checkinteger(L, 7);
threshold_hi = luaL_checkinteger(L, 8);
luaL_argcheck(L, (int16_t)threshold_low <= (int16_t)threshold_hi, 7, "threshold_low > threshold_hi");
luaL_argcheck(L, get_value(gain, channel, &threshold_low), 7, unexpected_value);
luaL_argcheck(L, get_value(gain, channel, &threshold_hi), 8, unexpected_value);
} }
ads_ctrl->threshold_low = threshold_low;
if (get_value(&ads1115_threshold_hi)) { ads_ctrl->threshold_hi = threshold_hi;
return luaL_error(L, "Invalid argument: threshold_hi"); NODE_DBG("ads1115 low: %04x\n", threshold_low);
NODE_DBG("ads1115 hi : %04x\n", threshold_hi);
write_reg(ads_ctrl->i2c_addr, ADS1115_POINTER_THRESH_LOW, threshold_low);
write_reg(ads_ctrl->i2c_addr, ADS1115_POINTER_THRESH_HI, threshold_hi);
} }
ads_ctrl->comp = comp;
write_reg(ADS1115_POINTER_THRESH_LOW, ads1115_threshold_low); uint16_t comparator_mode = ADS1115_CMODE_TRAD;
write_reg(ADS1115_POINTER_THRESH_HI, ads1115_threshold_hi); if (argc == 9) {
comparator_mode = luaL_checkinteger(L, 9);
luaL_argcheck(L, (comparator_mode == ADS1115_CMODE_WINDOW) || (comparator_mode == ADS1115_CMODE_TRAD),
9, unexpected_value);
} }
ads1115_config = (ads1115_os | ads1115_channel | ads1115_gain | ads1115_mode | ads1115_samples | ADS1115_CMODE_TRAD | ADS1115_CPOL_ACTVLOW | ADS1115_CLAT_NONLAT | ads1115_comp); uint16_t config = (os | channel | gain | mode | samples | comparator_mode | ADS1115_CPOL_ACTVLOW | ADS1115_CLAT_NONLAT | comp);
ads_ctrl->config = config;
write_reg(ADS1115_POINTER_CONFIG, ads1115_config);
NODE_DBG("ads1115 config: %04x\n", ads_ctrl->config);
write_reg(ads_ctrl->i2c_addr, ADS1115_POINTER_CONFIG, config);
return 0; return 0;
} }
// Read the conversion register from the ADC // Read the conversion register from the ADC device
// Lua: ads1115.startread(function(volt, voltdec, adc) print(volt,voltdec,adc) end) // Lua: ads1115.device:startread(function(volt, voltdec, adc, sign) print(volt,voltdec,adc,sign) end)
static int ads1115_lua_startread(lua_State *L) { static int ads1115_lua_startread(lua_State *L) {
ads_ctrl_ud_t *ads_ctrl = luaL_checkudata(L, 1, metatable_name);
if (((ads1115_comp == ADS1115_CQUE_1CONV) || (ads1115_comp == ADS1115_CQUE_2CONV) || (ads1115_comp == ADS1115_CQUE_4CONV)) && (ads1115_threshold_low == 0x7FFF) && (ads1115_threshold_hi == 0x8000)) { if (((ads_ctrl->comp == ADS1115_CQUE_1CONV) ||
(ads_ctrl->comp == ADS1115_CQUE_2CONV) ||
if (ads1115_mode == ADS1115_MODE_SINGLE) { (ads_ctrl->comp == ADS1115_CQUE_4CONV)) &&
write_reg(ADS1115_POINTER_CONFIG, ads1115_config); (ads_ctrl->threshold_low == 0x7FFF) &&
(ads_ctrl->threshold_hi == 0x8000)) {
// conversion ready mode
if (ads_ctrl->mode == ADS1115_MODE_SINGLE) {
NODE_DBG("ads1115 trigger config: %04x", ads_ctrl->config);
write_reg(ads_ctrl->i2c_addr, ADS1115_POINTER_CONFIG, ads_ctrl->config);
} }
return 0; return 0;
}
} else { luaL_argcheck(L, (lua_type(L, 2) == LUA_TFUNCTION || lua_type(L, 2) == LUA_TLIGHTFUNCTION), 2, "Must be function");
lua_pushvalue(L, 2);
luaL_argcheck(L, (lua_type(L, 1) == LUA_TFUNCTION || lua_type(L, 1) == LUA_TLIGHTFUNCTION), 1, "Must be function"); ads_ctrl->timer_ref = luaL_ref(L, LUA_REGISTRYINDEX);
lua_pushvalue(L, 1);
ads1115_timer_ref = luaL_ref(L, LUA_REGISTRYINDEX);
if (ads1115_mode == ADS1115_MODE_SINGLE) { if (ads_ctrl->mode == ADS1115_MODE_SINGLE) {
write_reg(ADS1115_POINTER_CONFIG, ads1115_config); write_reg(ads_ctrl->i2c_addr, ADS1115_POINTER_CONFIG, ads_ctrl->config);
} }
// Start a timer to wait until ADC conversion is done // Start a timer to wait until ADC conversion is done
os_timer_disarm (&ads1115_timer); os_timer_disarm(&ads_ctrl->timer);
os_timer_setfn (&ads1115_timer, (os_timer_func_t *)ads1115_lua_readoutdone, NULL); os_timer_setfn(&ads_ctrl->timer, (os_timer_func_t *)ads1115_lua_readoutdone, (void *)ads_ctrl);
switch (ads1115_samples) { int msec = 1; // ADS1115_DR_1600SPS, ADS1115_DR_2400SPS, ADS1115_DR_3300SPS
case (ADS1115_DR_8SPS): switch (ads_ctrl->samples_value) {
os_timer_arm (&ads1115_timer, 150, 0); case ADS1115_DR_8SPS:
break; msec = 150;
case (ADS1115_DR_16SPS):
os_timer_arm (&ads1115_timer, 75, 0);
break; break;
case (ADS1115_DR_32SPS): case ADS1115_DR_16SPS:
os_timer_arm (&ads1115_timer, 35, 0); msec = 75;
break; break;
case (ADS1115_DR_64SPS): case ADS1115_DR_32SPS:
os_timer_arm (&ads1115_timer, 20, 0); msec = 35;
break; break;
case (ADS1115_DR_128SPS): case ADS1115_DR_64SPS:
os_timer_arm (&ads1115_timer, 10, 0); msec = 20;
break; break;
case (ADS1115_DR_250SPS): case ADS1115_DR_128SPS:
os_timer_arm (&ads1115_timer, 5, 0); msec = 10;
break; break;
case (ADS1115_DR_475SPS): case ADS1115_DR_250SPS:
os_timer_arm (&ads1115_timer, 3, 0); msec = 5;
break; break;
case (ADS1115_DR_860SPS): case ADS1115_DR_475SPS:
os_timer_arm (&ads1115_timer, 2, 0); case ADS1115_DR_490SPS:
msec = 3;
break; break;
case ADS1115_DR_860SPS:
case ADS1115_DR_920SPS:
msec = 2;
} }
os_timer_arm(&ads_ctrl->timer, msec, 0);
return 0; return 0;
}
} }
// adc conversion timer callback static void read_common(ads_ctrl_ud_t * ads_ctrl, uint16_t raw, lua_State *L) {
static int ads1115_lua_readoutdone(void) { double mvolt = get_mvolt(ads_ctrl->gain, raw);
#ifdef LUA_NUMBER_INTEGRAL
int sign;
if (mvolt == 0) {
sign = 0;
} else if (mvolt > 0) {
sign = 1;
} else {
sign = -1;
}
int uvolt;
if (sign >= 0) {
uvolt = (int)((mvolt - (int)mvolt) * 1000 + 0.5);
} else {
uvolt = -(int)((mvolt - (int)mvolt) * 1000 - 0.5);
mvolt = -mvolt;
}
lua_pushnumber(L, mvolt);
lua_pushinteger(L, uvolt);
lua_pushinteger(L, raw);
lua_pushinteger(L, sign);
#else
lua_pushnumber(L, mvolt);
lua_pushnil(L);
lua_pushinteger(L, raw);
lua_pushnil(L);
#endif
}
ads1115_conversion = read_reg(ADS1115_POINTER_CONVERSION);
ads1115_volt = get_volt(ads1115_conversion);
int ads1115_voltdec = (int)((ads1115_volt - (int)ads1115_volt) * 1000);
ads1115_voltdec = ads1115_voltdec>0?ads1115_voltdec:0-ads1115_voltdec;
// adc conversion timer callback
static int ads1115_lua_readoutdone(void * param) {
ads_ctrl_ud_t * ads_ctrl = (ads_ctrl_ud_t *)param;
uint16_t raw = read_reg(ads_ctrl->i2c_addr, ADS1115_POINTER_CONVERSION);
lua_State *L = lua_getstate(); lua_State *L = lua_getstate();
os_timer_disarm (&ads1115_timer); os_timer_disarm(&ads_ctrl->timer);
lua_rawgeti(L, LUA_REGISTRYINDEX, ads_ctrl->timer_ref);
lua_rawgeti (L, LUA_REGISTRYINDEX, ads1115_timer_ref); luaL_unref(L, LUA_REGISTRYINDEX, ads_ctrl->timer_ref);
luaL_unref (L, LUA_REGISTRYINDEX, ads1115_timer_ref); ads_ctrl->timer_ref = LUA_NOREF;
ads1115_timer_ref = LUA_NOREF; read_common(ads_ctrl, raw, L);
lua_call(L, 4, 0);
lua_pushnumber(L, ads1115_volt);
lua_pushinteger(L, ads1115_voltdec);
lua_pushinteger(L, ads1115_conversion);
lua_call (L, 3, 0);
} }
// Read the conversion register from the ADC // Read the conversion register from the ADC device
// Lua: volt,voltdec,adc = ads1115.read() // Lua: volt,voltdec,adc,sign = ads1115.device:read()
static int ads1115_lua_read(lua_State *L) { static int ads1115_lua_read(lua_State *L) {
ads_ctrl_ud_t *ads_ctrl = luaL_checkudata(L, 1, metatable_name);
uint16_t raw = read_reg(ads_ctrl->i2c_addr, ADS1115_POINTER_CONVERSION);
read_common(ads_ctrl, raw, L);
return 4;
}
ads1115_conversion = read_reg(ADS1115_POINTER_CONVERSION); #ifdef ADS1115_INCLUDE_TEST_FUNCTION
ads1115_volt = get_volt(ads1115_conversion); // this function simulates conversion using raw value provided as argument
int ads1115_voltdec = (int)((ads1115_volt - (int)ads1115_volt) * 1000); // Lua: volt,volt_dec,adc,sign = ads1115.test_volt_conversion(-1)
ads1115_voltdec = ads1115_voltdec>0?ads1115_voltdec:0-ads1115_voltdec; static int test_volt_conversion(lua_State *L) {
ads_ctrl_ud_t *ads_ctrl = luaL_checkudata(L, 1, metatable_name);
lua_pushnumber(L, ads1115_volt); uint16_t raw = luaL_checkinteger(L, 2);
lua_pushinteger(L, ads1115_voltdec); read_common(ads_ctrl, raw, L);
lua_pushinteger(L, ads1115_conversion); return 4;
}
#endif
return 3; static int ads1115_lua_delete(lua_State *L) {
ads_ctrl_ud_t *ads_ctrl = luaL_checkudata(L, 1, metatable_name);
if (ads_ctrl->timer_ref != LUA_NOREF) {
os_timer_disarm(&ads_ctrl->timer);
luaL_unref(L, LUA_REGISTRYINDEX, ads_ctrl->timer_ref);
}
return 0;
} }
static const LUA_REG_TYPE ads1115_map[] = { static const LUA_REG_TYPE ads1115_map[] = {
{ LSTRKEY( "setup" ), LFUNCVAL(ads1115_lua_setup) },
{ LSTRKEY( "setting" ), LFUNCVAL(ads1115_lua_setting) }, { LSTRKEY( "ads1115" ), LFUNCVAL(ads1115_lua_register_1115) },
{ LSTRKEY( "startread" ), LFUNCVAL(ads1115_lua_startread) }, { LSTRKEY( "ads1015" ), LFUNCVAL(ads1115_lua_register_1015) },
{ LSTRKEY( "read" ), LFUNCVAL(ads1115_lua_read) }, { LSTRKEY( "reset" ), LFUNCVAL(ads1115_lua_reset) },
{ LSTRKEY( "ADDR_GND" ), LNUMVAL(ADS1115_I2C_ADDR_GND) }, { LSTRKEY( "ADDR_GND" ), LNUMVAL(ADS1115_I2C_ADDR_GND) },
{ LSTRKEY( "ADDR_VDD" ), LNUMVAL(ADS1115_I2C_ADDR_VDD) }, { LSTRKEY( "ADDR_VDD" ), LNUMVAL(ADS1115_I2C_ADDR_VDD) },
{ LSTRKEY( "ADDR_SDA" ), LNUMVAL(ADS1115_I2C_ADDR_SDA) }, { LSTRKEY( "ADDR_SDA" ), LNUMVAL(ADS1115_I2C_ADDR_SDA) },
...@@ -435,14 +563,39 @@ static const LUA_REG_TYPE ads1115_map[] = { ...@@ -435,14 +563,39 @@ static const LUA_REG_TYPE ads1115_map[] = {
{ LSTRKEY( "DR_128SPS" ), LNUMVAL(ADS1115_DR_128SPS) }, { LSTRKEY( "DR_128SPS" ), LNUMVAL(ADS1115_DR_128SPS) },
{ LSTRKEY( "DR_250SPS" ), LNUMVAL(ADS1115_DR_250SPS) }, { LSTRKEY( "DR_250SPS" ), LNUMVAL(ADS1115_DR_250SPS) },
{ LSTRKEY( "DR_475SPS" ), LNUMVAL(ADS1115_DR_475SPS) }, { LSTRKEY( "DR_475SPS" ), LNUMVAL(ADS1115_DR_475SPS) },
{ LSTRKEY( "DR_490SPS" ), LNUMVAL(ADS1115_DR_490SPS) },
{ LSTRKEY( "DR_860SPS" ), LNUMVAL(ADS1115_DR_860SPS) }, { LSTRKEY( "DR_860SPS" ), LNUMVAL(ADS1115_DR_860SPS) },
{ LSTRKEY( "DR_920SPS" ), LNUMVAL(ADS1115_DR_920SPS) },
{ LSTRKEY( "DR_1600SPS" ), LNUMVAL(ADS1115_DR_1600SPS) },
{ LSTRKEY( "DR_2400SPS" ), LNUMVAL(ADS1115_DR_2400SPS) },
{ LSTRKEY( "DR_3300SPS" ), LNUMVAL(ADS1115_DR_3300SPS) },
{ LSTRKEY( "CONV_RDY_1" ), LNUMVAL(ADS1115_CQUE_1CONV) }, { LSTRKEY( "CONV_RDY_1" ), LNUMVAL(ADS1115_CQUE_1CONV) },
{ LSTRKEY( "CONV_RDY_2" ), LNUMVAL(ADS1115_CQUE_2CONV) }, { LSTRKEY( "CONV_RDY_2" ), LNUMVAL(ADS1115_CQUE_2CONV) },
{ LSTRKEY( "CONV_RDY_4" ), LNUMVAL(ADS1115_CQUE_4CONV) }, { LSTRKEY( "CONV_RDY_4" ), LNUMVAL(ADS1115_CQUE_4CONV) },
{ LSTRKEY( "COMP_1CONV" ), LNUMVAL(ADS1115_CQUE_1CONV) }, { LSTRKEY( "COMP_1CONV" ), LNUMVAL(ADS1115_CQUE_1CONV) },
{ LSTRKEY( "COMP_2CONV" ), LNUMVAL(ADS1115_CQUE_2CONV) }, { LSTRKEY( "COMP_2CONV" ), LNUMVAL(ADS1115_CQUE_2CONV) },
{ LSTRKEY( "COMP_4CONV" ), LNUMVAL(ADS1115_CQUE_4CONV) }, { LSTRKEY( "COMP_4CONV" ), LNUMVAL(ADS1115_CQUE_4CONV) },
{ LSTRKEY( "CMODE_TRAD"), LNUMVAL(ADS1115_CMODE_TRAD) },
{ LSTRKEY( "CMODE_WINDOW"), LNUMVAL(ADS1115_CMODE_WINDOW) },
{ LNILKEY, LNILVAL }
};
static const LUA_REG_TYPE ads1115_instance_map[] = {
{ LSTRKEY( "setting" ), LFUNCVAL(ads1115_lua_setting) },
{ LSTRKEY( "startread" ), LFUNCVAL(ads1115_lua_startread) },
{ LSTRKEY( "read" ), LFUNCVAL(ads1115_lua_read) },
#ifdef ADS1115_INCLUDE_TEST_FUNCTION
{ LSTRKEY( "test_volt_conversion" ), LFUNCVAL(test_volt_conversion)},
#endif
{ LSTRKEY( "__index" ), LROVAL(ads1115_instance_map) },
{ LSTRKEY( "__gc" ), LFUNCVAL(ads1115_lua_delete) },
{ LNILKEY, LNILVAL } { LNILKEY, LNILVAL }
}; };
NODEMCU_MODULE(ADS1115, "ads1115", ads1115_map, NULL);
\ No newline at end of file int luaopen_ads1115(lua_State *L) {
luaL_rometatable(L, metatable_name, (void *)ads1115_instance_map);
return 0;
}
NODEMCU_MODULE(ADS1115, "ads1115", ads1115_map, luaopen_ads1115);
...@@ -45,23 +45,6 @@ static int adxl345_setup(lua_State* L) { ...@@ -45,23 +45,6 @@ static int adxl345_setup(lua_State* L) {
return 0; return 0;
} }
static int adxl345_init(lua_State* L) {
uint32_t sda;
uint32_t scl;
platform_print_deprecation_note("adxl345.init() is replaced by adxl345.setup()", "in the next version");
sda = luaL_checkinteger(L, 1);
scl = luaL_checkinteger(L, 2);
luaL_argcheck(L, sda > 0 && scl > 0, 1, "no i2c for D0");
platform_i2c_setup(adxl345_i2c_id, sda, scl, PLATFORM_I2C_SPEED_SLOW);
return adxl345_setup(L);
}
static int adxl345_read(lua_State* L) { static int adxl345_read(lua_State* L) {
uint8_t data[6]; uint8_t data[6];
...@@ -96,8 +79,6 @@ static int adxl345_read(lua_State* L) { ...@@ -96,8 +79,6 @@ static int adxl345_read(lua_State* L) {
static const LUA_REG_TYPE adxl345_map[] = { static const LUA_REG_TYPE adxl345_map[] = {
{ LSTRKEY( "read" ), LFUNCVAL( adxl345_read )}, { LSTRKEY( "read" ), LFUNCVAL( adxl345_read )},
{ LSTRKEY( "setup" ), LFUNCVAL( adxl345_setup )}, { LSTRKEY( "setup" ), LFUNCVAL( adxl345_setup )},
/// init() is deprecated
{ LSTRKEY( "init" ), LFUNCVAL( adxl345_init )},
{ LNILKEY, LNILVAL} { LNILKEY, LNILVAL}
}; };
......
...@@ -106,29 +106,6 @@ static int am2320_setup(lua_State* L) ...@@ -106,29 +106,6 @@ static int am2320_setup(lua_State* L)
return 3; return 3;
} }
static int am2320_init(lua_State* L)
{
uint32_t sda;
uint32_t scl;
platform_print_deprecation_note("am2320.init() is replaced by am2320.setup()", "in the next version");
if (!lua_isnumber(L, 1) || !lua_isnumber(L, 2)) {
return luaL_error(L, "wrong arg range");
}
sda = luaL_checkinteger(L, 1);
scl = luaL_checkinteger(L, 2);
if (scl == 0 || sda == 0) {
return luaL_error(L, "no i2c for D0");
}
platform_i2c_setup(am2320_i2c_id, sda, scl, PLATFORM_I2C_SPEED_SLOW);
return am2320_setup(L);
}
static int am2320_read(lua_State* L) static int am2320_read(lua_State* L)
{ {
int ret; int ret;
...@@ -155,8 +132,6 @@ static int am2320_read(lua_State* L) ...@@ -155,8 +132,6 @@ static int am2320_read(lua_State* L)
static const LUA_REG_TYPE am2320_map[] = { static const LUA_REG_TYPE am2320_map[] = {
{ LSTRKEY( "read" ), LFUNCVAL( am2320_read )}, { LSTRKEY( "read" ), LFUNCVAL( am2320_read )},
{ LSTRKEY( "setup" ), LFUNCVAL( am2320_setup )}, { LSTRKEY( "setup" ), LFUNCVAL( am2320_setup )},
// init() is deprecated
{ LSTRKEY( "init" ), LFUNCVAL( am2320_init )},
{ LNILKEY, LNILVAL} { LNILKEY, LNILVAL}
}; };
......
/*
* Module for bloom filters
*
* Philip Gladstone, N1DQ
*/
#include "module.h"
#include "lauxlib.h"
#include "c_types.h"
#include "../crypto/sha2.h"
#if defined(LUA_USE_MODULES_BLOOM) && !defined(SHA2_ENABLE)
#error Must have SHA2_ENABLE set for BLOOM module
#endif
typedef struct {
uint8 fns;
uint16 size;
uint32 occupancy;
uint32 buf[];
} bloom_t;
static bool add_or_check(const uint8 *buf, size_t len, bloom_t *filter, bool add) {
SHA256_CTX ctx;
SHA256_Init(&ctx);
SHA256_Update(&ctx, buf, len);
char hash[32];
SHA256_Final(hash, &ctx);
int i;
uint32 bits = filter->size << 5;
uint8 *h = hash;
bool prev = true;
int hstep = filter->fns > 10 ? 2 : 3;
for (i = 0; i < filter->fns; i++) {
uint32 val = (((h[0] << 8) + h[1]) << 8) + h[2];
h += hstep;
val = val % bits;
uint32 offset = val >> 5;
uint32 bit = 1 << (val & 31);
if (!(filter->buf[offset] & bit)) {
prev = false;
if (add) {
filter->buf[offset] |= bit;
filter->occupancy++;
} else {
break;
}
}
}
return prev;
}
static int bloom_filter_check(lua_State *L) {
bloom_t *filter = (bloom_t *)luaL_checkudata(L, 1, "bloom.filter");
size_t length;
const uint8 *buffer = (uint8 *) luaL_checklstring(L, 2, &length);
bool rc = add_or_check(buffer, length, filter, false);
lua_pushboolean(L, rc);
return 1;
}
static int bloom_filter_add(lua_State *L) {
bloom_t *filter = (bloom_t *)luaL_checkudata(L, 1, "bloom.filter");
size_t length;
const uint8 *buffer = (uint8 *) luaL_checklstring(L, 2, &length);
bool rc = add_or_check(buffer, length, filter, true);
lua_pushboolean(L, rc);
return 1;
}
static int bloom_filter_reset(lua_State *L) {
bloom_t *filter = (bloom_t *)luaL_checkudata(L, 1, "bloom.filter");
memset(filter->buf, 0, filter->size << 2);
filter->occupancy = 0;
return 0;
}
static int bloom_filter_info(lua_State *L) {
bloom_t *filter = (bloom_t *)luaL_checkudata(L, 1, "bloom.filter");
lua_pushinteger(L, filter->size << 5);
lua_pushinteger(L, filter->fns);
lua_pushinteger(L, filter->occupancy);
// Now calculate the chance that a FP will be returned
uint64 prob = 1000000;
if (filter->occupancy > 0) {
unsigned int ratio = (filter->size << 5) / filter->occupancy;
int i;
prob = ratio;
for (i = 1; i < filter->fns && prob < 1000000; i++) {
prob = prob * ratio;
}
if (prob < 1000000) {
// try again with some scaling
unsigned int ratio256 = (filter->size << 13) / filter->occupancy;
uint64 prob256 = ratio256;
for (i = 1; i < filter->fns && prob256 < 256000000; i++) {
prob256 = (prob256 * ratio256) >> 8;
}
prob = prob256 >> 8;
}
}
lua_pushinteger(L, prob > 1000000 ? 1000000 : (int) prob);
return 4;
}
static int bloom_create(lua_State *L) {
int items = luaL_checkinteger(L, 1);
int error = luaL_checkinteger(L, 2);
int n = error;
int logp = 0;
while (n > 0) {
n = n >> 1;
logp--;
}
int bits = -items * logp;
bits += bits >> 1;
bits = (bits + 31) & ~31;
if (bits < 256) {
bits = 256;
}
int size = bits >> 3;
int fns = bits / items;
fns = (fns >> 1) + fns / 6;
if (fns < 2) {
fns = 2;
}
if (fns > 15) {
fns = 15;
}
bloom_t *filter = (bloom_t *) lua_newuserdata(L, sizeof(bloom_t) + size);
//
// Associate its metatable
luaL_getmetatable(L, "bloom.filter");
lua_setmetatable(L, -2);
memset(filter, 0, sizeof(bloom_t) + size);
filter->size = size >> 2;
filter->fns = fns;
return 1;
}
static const LUA_REG_TYPE bloom_filter_map[] = {
{ LSTRKEY( "add" ), LFUNCVAL( bloom_filter_add ) },
{ LSTRKEY( "check" ), LFUNCVAL( bloom_filter_check ) },
{ LSTRKEY( "reset" ), LFUNCVAL( bloom_filter_reset ) },
{ LSTRKEY( "info" ), LFUNCVAL( bloom_filter_info ) },
{ LSTRKEY( "__index" ), LROVAL( bloom_filter_map ) },
{ LNILKEY, LNILVAL }
};
// Module function map
static const LUA_REG_TYPE bloom_map[] = {
{ LSTRKEY( "create" ), LFUNCVAL( bloom_create ) },
{ LNILKEY, LNILVAL }
};
LUALIB_API int bloom_open(lua_State *L) {
luaL_rometatable(L, "bloom.filter", (void *)bloom_filter_map);
return 1;
}
NODEMCU_MODULE(BLOOM, "bloom", bloom_map, bloom_open);
...@@ -314,30 +314,6 @@ static int bme280_lua_setup(lua_State* L) { ...@@ -314,30 +314,6 @@ static int bme280_lua_setup(lua_State* L) {
return 1; return 1;
} }
static int bme280_lua_init(lua_State* L) {
uint8_t sda;
uint8_t scl;
uint8_t config;
uint8_t ack;
uint8_t full_init;
platform_print_deprecation_note("bme280.init() is replaced by bme280.setup()", "in the next version");
if (!lua_isnumber(L, 1) || !lua_isnumber(L, 2)) {
return luaL_error(L, "wrong arg range");
}
sda = luaL_checkinteger(L, 1);
scl = luaL_checkinteger(L, 2);
platform_i2c_setup(bme280_i2c_id, sda, scl, PLATFORM_I2C_SPEED_SLOW);
// remove sda and scl parameters from stack
lua_remove(L, 1);
lua_remove(L, 1);
return bme280_lua_setup(L);
}
static void bme280_readoutdone (void *arg) static void bme280_readoutdone (void *arg)
{ {
NODE_DBG("timer out\n"); NODE_DBG("timer out\n");
...@@ -495,8 +471,6 @@ static int bme280_lua_dewpoint(lua_State* L) { ...@@ -495,8 +471,6 @@ static int bme280_lua_dewpoint(lua_State* L) {
} }
static const LUA_REG_TYPE bme280_map[] = { static const LUA_REG_TYPE bme280_map[] = {
// init() is deprecated
{ LSTRKEY( "init" ), LFUNCVAL(bme280_lua_init)},
{ LSTRKEY( "setup" ), LFUNCVAL(bme280_lua_setup)}, { LSTRKEY( "setup" ), LFUNCVAL(bme280_lua_setup)},
{ LSTRKEY( "temp" ), LFUNCVAL(bme280_lua_temp)}, { LSTRKEY( "temp" ), LFUNCVAL(bme280_lua_temp)},
{ LSTRKEY( "baro" ), LFUNCVAL(bme280_lua_baro)}, { LSTRKEY( "baro" ), LFUNCVAL(bme280_lua_baro)},
......
// ***************************************************************************
// Port of BMP680 module for ESP8266 with nodeMCU
//
// Written by Lukas Voborsky, @voborsky
// ***************************************************************************
// #define NODE_DEBUG
#include "module.h"
#include "lauxlib.h"
#include "platform.h"
#include "c_math.h"
#include "bme680_defs.h"
#define DEFAULT_HEATER_DUR 100
#define DEFAULT_HEATER_TEMP 300
#define DEFAULT_AMBIENT_TEMP 23
static const uint32_t bme680_i2c_id = BME680_CHIP_ID_ADDR;
static uint8_t bme680_i2c_addr = BME680_I2C_ADDR_PRIMARY;
os_timer_t bme680_timer; // timer for forced mode readout
int lua_connected_readout_ref; // callback when readout is ready
static struct bme680_calib_data bme680_data;
static uint8_t bme680_mode = 0; // stores oversampling settings
static uint8 os_temp = 0;
static uint8 os_pres = 0;
static uint8 os_hum = 0; // stores humidity oversampling settings
static uint16_t heatr_dur;
static int8_t amb_temp = 23; //DEFAULT_AMBIENT_TEMP;
static uint32_t bme680_h = 0;
static double bme680_hc = 1.0;
// return 0 if good
static int r8u_n(uint8_t reg, int n, uint8_t *buff) {
int i;
platform_i2c_send_start(bme680_i2c_id);
platform_i2c_send_address(bme680_i2c_id, bme680_i2c_addr, PLATFORM_I2C_DIRECTION_TRANSMITTER);
platform_i2c_send_byte(bme680_i2c_id, reg);
// platform_i2c_send_stop(bme680_i2c_id); // doco says not needed
platform_i2c_send_start(bme680_i2c_id);
platform_i2c_send_address(bme680_i2c_id, bme680_i2c_addr, PLATFORM_I2C_DIRECTION_RECEIVER);
while (n-- > 0)
*buff++ = platform_i2c_recv_byte(bme680_i2c_id, n > 0);
platform_i2c_send_stop(bme680_i2c_id);
return 0;
}
static uint8_t w8u(uint8_t reg, uint8_t val) {
platform_i2c_send_start(bme680_i2c_id);
platform_i2c_send_address(bme680_i2c_id, bme680_i2c_addr, PLATFORM_I2C_DIRECTION_TRANSMITTER);
platform_i2c_send_byte(bme680_i2c_id, reg);
platform_i2c_send_byte(bme680_i2c_id, val);
platform_i2c_send_stop(bme680_i2c_id);
}
static uint8_t r8u(uint8_t reg) {
uint8_t ret[1];
r8u_n(reg, 1, ret);
return ret[0];
}
/* This part of code is coming from the original bme680.c driver by Bosch.
* Copyright (C) 2017 - 2018 Bosch Sensortec GmbH
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* Neither the name of the copyright holder nor the names of the
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER
* OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES(INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
*
* The information provided is believed to be accurate and reliable.
* The copyright holder assumes no responsibility
* for the consequences of use
* of such information nor for any infringement of patents or
* other rights of third parties which may result from its use.
* No license is granted by implication or otherwise under any patent or
* patent rights of the copyright holder.
*/
/**static variables */
/**Look up table for the possible gas range values */
uint32_t lookupTable1[16] = { UINT32_C(2147483647), UINT32_C(2147483647), UINT32_C(2147483647), UINT32_C(2147483647),
UINT32_C(2147483647), UINT32_C(2126008810), UINT32_C(2147483647), UINT32_C(2130303777), UINT32_C(2147483647),
UINT32_C(2147483647), UINT32_C(2143188679), UINT32_C(2136746228), UINT32_C(2147483647), UINT32_C(2126008810),
UINT32_C(2147483647), UINT32_C(2147483647) };
/**Look up table for the possible gas range values */
uint32_t lookupTable2[16] = { UINT32_C(4096000000), UINT32_C(2048000000), UINT32_C(1024000000), UINT32_C(512000000),
UINT32_C(255744255), UINT32_C(127110228), UINT32_C(64000000), UINT32_C(32258064), UINT32_C(16016016), UINT32_C(
8000000), UINT32_C(4000000), UINT32_C(2000000), UINT32_C(1000000), UINT32_C(500000), UINT32_C(250000),
UINT32_C(125000) };
static uint8_t calc_heater_res(uint16_t temp)
{
uint8_t heatr_res;
int32_t var1;
int32_t var2;
int32_t var3;
int32_t var4;
int32_t var5;
int32_t heatr_res_x100;
if (temp < 200) /* Cap temperature */
temp = 200;
else if (temp > 400)
temp = 400;
var1 = (((int32_t) amb_temp * bme680_data.par_gh3) / 1000) * 256;
var2 = (bme680_data.par_gh1 + 784) * (((((bme680_data.par_gh2 + 154009) * temp * 5) / 100) + 3276800) / 10);
var3 = var1 + (var2 / 2);
var4 = (var3 / (bme680_data.res_heat_range + 4));
var5 = (131 * bme680_data.res_heat_val) + 65536;
heatr_res_x100 = (int32_t) (((var4 / var5) - 250) * 34);
heatr_res = (uint8_t) ((heatr_res_x100 + 50) / 100);
return heatr_res;
}
static uint8_t calc_heater_dur(uint16_t dur)
{
uint8_t factor = 0;
uint8_t durval;
if (dur >= 0xfc0) {
durval = 0xff; /* Max duration*/
} else {
while (dur > 0x3F) {
dur = dur / 4;
factor += 1;
}
durval = (uint8_t) (dur + (factor * 64));
}
return durval;
}
static int16_t calc_temperature(uint32_t temp_adc)
{
int64_t var1;
int64_t var2;
int64_t var3;
int16_t calc_temp;
var1 = ((int32_t) temp_adc / 8) - ((int32_t) bme680_data.par_t1 * 2);
var2 = (var1 * (int32_t) bme680_data.par_t2) / 2048;
var3 = ((var1 / 2) * (var1 / 2)) / 4096;
var3 = ((var3) * ((int32_t) bme680_data.par_t3 * 16)) / 16384;
bme680_data.t_fine = (int32_t) (var2 + var3);
calc_temp = (int16_t) (((bme680_data.t_fine * 5) + 128) / 256);
return calc_temp;
}
static uint32_t calc_pressure(uint32_t pres_adc)
{
int32_t var1;
int32_t var2;
int32_t var3;
int32_t calc_pres;
var1 = (((int32_t) bme680_data.t_fine) / 2) - 64000;
var2 = ((var1 / 4) * (var1 / 4)) / 2048;
var2 = ((var2) * (int32_t) bme680_data.par_p6) / 4;
var2 = var2 + ((var1 * (int32_t) bme680_data.par_p5) * 2);
var2 = (var2 / 4) + ((int32_t) bme680_data.par_p4 * 65536);
var1 = ((var1 / 4) * (var1 / 4)) / 8192;
var1 = (((var1) * ((int32_t) bme680_data.par_p3 * 32)) / 8) + (((int32_t) bme680_data.par_p2 * var1) / 2);
var1 = var1 / 262144;
var1 = ((32768 + var1) * (int32_t) bme680_data.par_p1) / 32768;
calc_pres = (int32_t) (1048576 - pres_adc);
calc_pres = (int32_t) ((calc_pres - (var2 / 4096)) * (3125));
calc_pres = ((calc_pres / var1) * 2);
var1 = ((int32_t) bme680_data.par_p9 * (int32_t) (((calc_pres / 8) * (calc_pres / 8)) / 8192)) / 4096;
var2 = ((int32_t) (calc_pres / 4) * (int32_t) bme680_data.par_p8) / 8192;
var3 = ((int32_t) (calc_pres / 256) * (int32_t) (calc_pres / 256) * (int32_t) (calc_pres / 256)
* (int32_t) bme680_data.par_p10) / 131072;
calc_pres = (int32_t) (calc_pres) + ((var1 + var2 + var3 + ((int32_t) bme680_data.par_p7 * 128)) / 16);
return (uint32_t) calc_pres;
}
static uint32_t calc_humidity(uint16_t hum_adc)
{
int32_t var1;
int32_t var2;
int32_t var3;
int32_t var4;
int32_t var5;
int32_t var6;
int32_t temp_scaled;
int32_t calc_hum;
temp_scaled = (((int32_t) bme680_data.t_fine * 5) + 128) / 256;
var1 = (int32_t) (hum_adc - ((int32_t) ((int32_t) bme680_data.par_h1 * 16)))
- (((temp_scaled * (int32_t) bme680_data.par_h3) / ((int32_t) 100)) / 2);
var2 = ((int32_t) bme680_data.par_h2
* (((temp_scaled * (int32_t) bme680_data.par_h4) / ((int32_t) 100))
+ (((temp_scaled * ((temp_scaled * (int32_t) bme680_data.par_h5) / ((int32_t) 100))) / 64)
/ ((int32_t) 100)) + (int32_t) (1 * 16384))) / 1024;
var3 = var1 * var2;
var4 = (int32_t) bme680_data.par_h6 * 128;
var4 = ((var4) + ((temp_scaled * (int32_t) bme680_data.par_h7) / ((int32_t) 100))) / 16;
var5 = ((var3 / 16384) * (var3 / 16384)) / 1024;
var6 = (var4 * var5) / 2;
calc_hum = (((var3 + var6) / 1024) * ((int32_t) 1000)) / 4096;
if (calc_hum > 100000) /* Cap at 100%rH */
calc_hum = 100000;
else if (calc_hum < 0)
calc_hum = 0;
return (uint32_t) calc_hum;
}
static uint32_t calc_gas_resistance(uint16_t gas_res_adc, uint8_t gas_range)
{
int64_t var1;
uint64_t var2;
int64_t var3;
uint32_t calc_gas_res;
var1 = (int64_t) ((1340 + (5 * (int64_t) bme680_data.range_sw_err)) * ((int64_t) lookupTable1[gas_range])) / 65536;
var2 = (((int64_t) ((int64_t) gas_res_adc * 32768) - (int64_t) (16777216)) + var1);
var3 = (((int64_t) lookupTable2[gas_range] * (int64_t) var1) / 512);
calc_gas_res = (uint32_t) ((var3 + ((int64_t) var2 / 2)) / (int64_t) var2);
return calc_gas_res;
}
uint16_t calc_dur()
{
uint32_t tph_dur; /* Calculate in us */
/* TPH measurement duration */
tph_dur = ((uint32_t) (os_temp + os_pres + os_hum) * UINT32_C(1963));
tph_dur += UINT32_C(477 * 4); /* TPH switching duration */
tph_dur += UINT32_C(477 * 5); /* Gas measurement duration */
tph_dur += UINT32_C(500); /* Get it to the closest whole number.*/
tph_dur /= UINT32_C(1000); /* Convert to ms */
tph_dur += UINT32_C(1); /* Wake up duration of 1ms */
NODE_DBG("tpc_dur: %d\n", tph_dur);
/* The remaining time should be used for heating */
return heatr_dur + (uint16_t) tph_dur;
}
/* This part of code is coming from the original bme680.c driver by Bosch.
* END */
static double ln(double x) {
double y = (x-1)/(x+1);
double y2 = y*y;
double r = 0;
for (int8_t i=33; i>0; i-=2) { //we've got the power
r = 1.0/(double)i + y2 * r;
}
return 2*y*r;
}
static double bme280_qfe2qnh(int32_t qfe, int32_t h) {
double hc;
if (bme680_h == h) {
hc = bme680_hc;
} else {
hc = pow((double)(1.0 - 2.25577e-5 * h), (double)(-5.25588));
bme680_hc = hc; bme680_h = h;
}
double qnh = (double)qfe * hc;
return qnh;
}
static int bme680_lua_setup(lua_State* L) {
uint8_t ack;
bme680_i2c_addr = BME680_I2C_ADDR_PRIMARY;
platform_i2c_send_start(bme680_i2c_id);
ack = platform_i2c_send_address(bme680_i2c_id, bme680_i2c_addr, PLATFORM_I2C_DIRECTION_TRANSMITTER);
platform_i2c_send_stop(bme680_i2c_id);
if (!ack) {
NODE_DBG("No ACK on address: %x\n", bme680_i2c_addr);
bme680_i2c_addr = BME680_I2C_ADDR_SECONDARY;
platform_i2c_send_start(bme680_i2c_id);
ack = platform_i2c_send_address(bme680_i2c_id, bme680_i2c_addr, PLATFORM_I2C_DIRECTION_TRANSMITTER);
platform_i2c_send_stop(bme680_i2c_id);
if (!ack) {
NODE_DBG("No ACK on address: %x\n", bme680_i2c_addr);
return 0;
}
}
uint8_t chipid = r8u(BME680_CHIP_ID_ADDR);
NODE_DBG("chip_id: %x\n", chipid);
#define r16uLE_buf(reg) (uint16_t)(((uint16_t)reg[1] << 8) | (uint16_t)reg[0])
#define r16sLE_buf(reg) (int16_t)(r16uLE_buf(reg))
uint8_t buff[BME680_COEFF_SIZE], *reg;
r8u_n(BME680_COEFF_ADDR1, BME680_COEFF_ADDR1_LEN, buff);
r8u_n(BME680_COEFF_ADDR2, BME680_COEFF_ADDR2_LEN, &buff[BME680_COEFF_ADDR1_LEN]);
reg = buff + 1;
bme680_data.par_t2 = r16sLE_buf(reg); reg+=2; // #define BME680_T3_REG (3)
bme680_data.par_t3 = (int8_t) reg[0]; reg+=2; // #define BME680_P1_LSB_REG (5)
bme680_data.par_p1 = r16uLE_buf(reg); reg+=2; // #define BME680_P2_LSB_REG (7)
bme680_data.par_p2 = r16sLE_buf(reg); reg+=2; // #define BME680_P3_REG (9)
bme680_data.par_p3 = (int8_t) reg[0]; reg+=2; // #define BME680_P4_LSB_REG (11)
bme680_data.par_p4 = r16sLE_buf(reg); reg+=2; // #define BME680_P5_LSB_REG (13)
bme680_data.par_p5 = r16sLE_buf(reg); reg+=2; // #define BME680_P7_REG (15)
bme680_data.par_p7 = (int8_t) reg[0]; reg++; // #define BME680_P6_REG (16)
bme680_data.par_p6 = (int8_t) reg[0]; reg+=3; // #define BME680_P8_LSB_REG (19)
bme680_data.par_p8 = r16sLE_buf(reg); reg+=2; // #define BME680_P9_LSB_REG (21)
bme680_data.par_p9 = r16sLE_buf(reg); reg+=2; // #define BME680_P10_REG (23)
bme680_data.par_p10 = (int8_t) reg[0]; reg+=2; // #define BME680_H2_MSB_REG (25)
bme680_data.par_h2 = (uint16_t) (((uint16_t) reg[0] << BME680_HUM_REG_SHIFT_VAL)
| ((reg[1]) >> BME680_HUM_REG_SHIFT_VAL)); reg++; // #define BME680_H1_LSB_REG (26)
bme680_data.par_h1 = (uint16_t) (((uint16_t) reg[1] << BME680_HUM_REG_SHIFT_VAL)
| (reg[0] & BME680_BIT_H1_DATA_MSK)); reg+=2; // #define BME680_H3_REG (28)
bme680_data.par_h3 = (int8_t) reg[0]; reg++; // #define BME680_H4_REG (29)
bme680_data.par_h4 = (int8_t) reg[0]; reg++; // #define BME680_H5_REG (30)
bme680_data.par_h5 = (int8_t) reg[0]; reg++; // #define BME680_H6_REG (31)
bme680_data.par_h6 = (uint8_t) reg[0]; reg++; // #define BME680_H7_REG (32)
bme680_data.par_h7 = (int8_t) reg[0]; reg++; // #define BME680_T1_LSB_REG (33)
bme680_data.par_t1 = r16uLE_buf(reg); reg+=2; // #define BME680_GH2_LSB_REG (35)
bme680_data.par_gh2 = r16sLE_buf(reg); reg+=2; // #define BME680_GH1_REG (37)
bme680_data.par_gh1 = reg[0]; reg++; // #define BME680_GH3_REG (38)
bme680_data.par_gh3 = reg[0];
#undef r16uLE_buf
#undef r16sLE_buf
/* Other coefficients */
bme680_data.res_heat_range = ((r8u(BME680_ADDR_RES_HEAT_RANGE_ADDR) & BME680_RHRANGE_MSK) / 16);
bme680_data.res_heat_val = (int8_t) r8u(BME680_ADDR_RES_HEAT_VAL_ADDR);
bme680_data.range_sw_err = ((int8_t) r8u(BME680_ADDR_RANGE_SW_ERR_ADDR) & (int8_t) BME680_RSERROR_MSK) / 16;
NODE_DBG("par_T: %d\t%d\t%d\n", bme680_data.par_t1, bme680_data.par_t2, bme680_data.par_t3);
NODE_DBG("par_P: %d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\n", bme680_data.par_p1, bme680_data.par_p2, bme680_data.par_p3, bme680_data.par_p4, bme680_data.par_p5, bme680_data.par_p6, bme680_data.par_p7, bme680_data.par_p8, bme680_data.par_p9, bme680_data.par_p10);
NODE_DBG("par_H: %d\t%d\t%d\t%d\t%d\t%d\t%d\n", bme680_data.par_h1, bme680_data.par_h2, bme680_data.par_h3, bme680_data.par_h4, bme680_data.par_h5, bme680_data.par_h6, bme680_data.par_h7);
NODE_DBG("par_GH: %d\t%d\t%d\n", bme680_data.par_gh1, bme680_data.par_gh2, bme680_data.par_gh3);
NODE_DBG("res_heat_range, res_heat_val, range_sw_err: %d\t%d\t%d\n", bme680_data.res_heat_range, bme680_data.res_heat_val, bme680_data.range_sw_err);
uint8_t full_init = !lua_isnumber(L, 7)?1:lua_tointeger(L, 7); // 7-th parameter: init the chip too
if (full_init) {
uint8_t filter;
uint8_t const bit3 = 0b111;
uint8_t const bit2 = 0b11;
//bme680.setup([temp_oss, press_oss, humi_oss, heater_temp, heater_duration, IIR_filter])
os_temp = (!lua_isnumber(L, 1)?BME680_OS_2X:(luaL_checkinteger(L, 1)&bit3)); // 1-st parameter: temperature oversampling
os_pres = (!lua_isnumber(L, 2)?BME680_OS_16X:(luaL_checkinteger(L, 2)&bit3)); // 2-nd parameter: pressure oversampling
os_hum = (!lua_isnumber(L, 3))?BME680_OS_1X:(luaL_checkinteger(L, 3)&bit3);
bme680_mode = BME680_SLEEP_MODE | (os_pres << 2) | (os_temp << 5);
os_hum = os_hum; // 3-rd parameter: humidity oversampling
filter = ((!lua_isnumber(L, 6)?BME680_FILTER_SIZE_31:(luaL_checkinteger(L, 6)&bit3)) << 2); // 6-th parameter: IIR filter
NODE_DBG("mode: %x\nhumidity oss: %x\nconfig: %x\n", bme680_mode, os_hum, filter);
heatr_dur = (!lua_isnumber(L, 5)?DEFAULT_HEATER_DUR:(luaL_checkinteger(L, 5))); // 5-th parameter: heater duration
w8u(BME680_GAS_WAIT0_ADDR, calc_heater_dur(heatr_dur));
w8u(BME680_RES_HEAT0_ADDR, calc_heater_res((!lua_isnumber(L, 4)?DEFAULT_HEATER_TEMP:(luaL_checkinteger(L, 4))))); // 4-th parameter: heater temperature
w8u(BME680_CONF_ODR_FILT_ADDR, BME680_SET_BITS_POS_0(r8u(BME680_CONF_ODR_FILT_ADDR), BME680_FILTER, filter)); // #define BME680_CONF_ODR_FILT_ADDR UINT8_C(0x75)
// set heater on
w8u(BME680_CONF_HEAT_CTRL_ADDR, BME680_SET_BITS_POS_0(r8u(BME680_CONF_HEAT_CTRL_ADDR), BME680_HCTRL, 1));
w8u(BME680_CONF_T_P_MODE_ADDR, bme680_mode);
w8u(BME680_CONF_OS_H_ADDR, BME680_SET_BITS_POS_0(r8u(BME680_CONF_OS_H_ADDR), BME680_OSH, os_hum));
w8u(BME680_CONF_ODR_RUN_GAS_NBC_ADDR, 1 << 4 | 0 & bit3);
}
lua_pushinteger(L, 1);
return 1;
}
static void bme280_readoutdone (void *arg)
{
NODE_DBG("timer out\n");
lua_State *L = lua_getstate();
lua_rawgeti (L, LUA_REGISTRYINDEX, lua_connected_readout_ref);
lua_call (L, 0, 0);
luaL_unref (L, LUA_REGISTRYINDEX, lua_connected_readout_ref);
os_timer_disarm (&bme680_timer);
}
static int bme680_lua_startreadout(lua_State* L) {
uint32_t delay;
if (lua_isnumber(L, 1)) {
delay = luaL_checkinteger(L, 1);
if (!delay) {delay = calc_dur();} // if delay is 0 then set the default delay
}
if (!lua_isnoneornil(L, 2)) {
lua_pushvalue(L, 2);
lua_connected_readout_ref = luaL_ref(L, LUA_REGISTRYINDEX);
} else {
lua_connected_readout_ref = LUA_NOREF;
}
w8u(BME680_CONF_OS_H_ADDR, os_hum);
w8u(BME680_CONF_T_P_MODE_ADDR, (bme680_mode & 0xFC) | BME680_FORCED_MODE);
NODE_DBG("control old: %x, control: %x, delay: %d\n", bme680_mode, (bme680_mode & 0xFC) | BME680_FORCED_MODE, delay);
if (lua_connected_readout_ref != LUA_NOREF) {
NODE_DBG("timer armed\n");
os_timer_disarm (&bme680_timer);
os_timer_setfn (&bme680_timer, (os_timer_func_t *)bme280_readoutdone, L);
os_timer_arm (&bme680_timer, delay, 0); // trigger callback when readout is ready
}
return 0;
}
// Return nothing on failure
// Return T, QFE, H if no altitude given
// Return T, QFE, H, QNH if altitude given
static int bme680_lua_read(lua_State* L) {
uint8_t buff[BME680_FIELD_LENGTH] = { 0 };
uint8_t gas_range;
uint32_t adc_temp;
uint32_t adc_pres;
uint16_t adc_hum;
uint16_t adc_gas_res;
uint8_t status;
uint32_t qfe;
uint8_t calc_qnh = lua_isnumber(L, 1);
r8u_n(BME680_FIELD0_ADDR, BME680_FIELD_LENGTH, buff);
status = buff[0] & BME680_NEW_DATA_MSK;
/* read the raw data from the sensor */
adc_pres = (uint32_t) (((uint32_t) buff[2] * 4096) | ((uint32_t) buff[3] * 16) | ((uint32_t) buff[4] / 16));
adc_temp = (uint32_t) (((uint32_t) buff[5] * 4096) | ((uint32_t) buff[6] * 16) | ((uint32_t) buff[7] / 16));
adc_hum = (uint16_t) (((uint32_t) buff[8] * 256) | (uint32_t) buff[9]);
adc_gas_res = (uint16_t) ((uint32_t) buff[13] * 4 | (((uint32_t) buff[14]) / 64));
gas_range = buff[14] & BME680_GAS_RANGE_MSK;
status |= buff[14] & BME680_GASM_VALID_MSK;
status |= buff[14] & BME680_HEAT_STAB_MSK;
NODE_DBG("status, new_data, gas_range, gasm_valid: 0x%x, 0x%x, 0x%x, 0x%x\n", status, status & BME680_NEW_DATA_MSK, buff[14] & BME680_GAS_RANGE_MSK, buff[14] & BME680_GASM_VALID_MSK);
if (!(status & BME680_NEW_DATA_MSK)) {
return 0;
}
int16_t temp = calc_temperature(adc_temp);
amb_temp = temp / 100;
lua_pushinteger(L, temp);
qfe = calc_pressure(adc_pres);
lua_pushinteger(L, qfe);
lua_pushinteger(L, calc_humidity(adc_hum));
lua_pushinteger(L, calc_gas_resistance(adc_gas_res, gas_range));
if (calc_qnh) { // have altitude
int32_t h = luaL_checkinteger(L, 1);
double qnh = bme280_qfe2qnh(qfe, h);
lua_pushinteger(L, (int32_t)(qnh + 0.5));
return 5;
}
return 4;
}
static int bme680_lua_qfe2qnh(lua_State* L) {
if (!lua_isnumber(L, 2)) {
return luaL_error(L, "wrong arg range");
}
int32_t qfe = luaL_checkinteger(L, 1);
int32_t h = luaL_checkinteger(L, 2);
double qnh = bme280_qfe2qnh(qfe, h);
lua_pushinteger(L, (int32_t)(qnh + 0.5));
return 1;
}
static int bme680_lua_altitude(lua_State* L) {
if (!lua_isnumber(L, 2)) {
return luaL_error(L, "wrong arg range");
}
int32_t P = luaL_checkinteger(L, 1);
int32_t qnh = luaL_checkinteger(L, 2);
double h = (1.0 - pow((double)P/(double)qnh, 1.0/5.25588)) / 2.25577e-5 * 100.0;
lua_pushinteger(L, (int32_t)(h + (((h<0)?-1:(h>0)) * 0.5)));
return 1;
}
static int bme680_lua_dewpoint(lua_State* L) {
if (!lua_isnumber(L, 2)) {
return luaL_error(L, "wrong arg range");
}
double H = luaL_checkinteger(L, 1)/100000.0;
double T = luaL_checkinteger(L, 2)/100.0;
const double c243 = 243.5;
const double c17 = 17.67;
double c = ln(H) + ((c17 * T) / (c243 + T));
double d = (c243 * c)/(c17 - c) * 100.0;
lua_pushinteger(L, (int32_t)(d + (((d<0)?-1:(d>0)) * 0.5)));
return 1;
}
static const LUA_REG_TYPE bme680_map[] = {
{ LSTRKEY( "setup" ), LFUNCVAL(bme680_lua_setup)},
{ LSTRKEY( "startreadout" ), LFUNCVAL(bme680_lua_startreadout)},
{ LSTRKEY( "qfe2qnh" ), LFUNCVAL(bme680_lua_qfe2qnh)},
{ LSTRKEY( "altitude" ), LFUNCVAL(bme680_lua_altitude)},
{ LSTRKEY( "dewpoint" ), LFUNCVAL(bme680_lua_dewpoint)},
{ LSTRKEY( "read" ), LFUNCVAL(bme680_lua_read)},
{ LNILKEY, LNILVAL}
};
NODEMCU_MODULE(BME680, "bme680", bme680_map, NULL);
/**
* Copyright (C) 2017 - 2018 Bosch Sensortec GmbH
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* Neither the name of the copyright holder nor the names of the
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER
* OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES(INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
*
* The information provided is believed to be accurate and reliable.
* The copyright holder assumes no responsibility
* for the consequences of use
* of such information nor for any infringement of patents or
* other rights of third parties which may result from its use.
* No license is granted by implication or otherwise under any patent or
* patent rights of the copyright holder.
*
* @file bme680_defs.h
* @date 5 Jul 2017
* @version 3.5.1
* @brief
*
*/
/*! @file bme680_defs.h
@brief Sensor driver for BME680 sensor */
/*!
* @defgroup BME680 SENSOR API
* @brief
* @{*/
#ifndef BME680_DEFS_H_
#define BME680_DEFS_H_
/********************************************************/
/* header includes */
#ifdef __KERNEL__
#include <linux/types.h>
#else
#include <stdint.h>
#endif
#ifdef __KERNEL__
#if (LONG_MAX) > 0x7fffffff
#define __have_long64 1
#elif (LONG_MAX) == 0x7fffffff
#define __have_long32 1
#endif
#if !defined(UINT8_C)
#define INT8_C(x) x
#if (INT_MAX) > 0x7f
#define UINT8_C(x) x
#else
#define UINT8_C(x) x##U
#endif
#endif
#if !defined(UINT16_C)
#define INT16_C(x) x
#if (INT_MAX) > 0x7fff
#define UINT16_C(x) x
#else
#define UINT16_C(x) x##U
#endif
#endif
#if !defined(INT32_C) && !defined(UINT32_C)
#if __have_long32
#define INT32_C(x) x##L
#define UINT32_C(x) x##UL
#else
#define INT32_C(x) x
#define UINT32_C(x) x##U
#endif
#endif
#if !defined(INT64_C) && !defined(UINT64_C)
#if __have_long64
#define INT64_C(x) x##L
#define UINT64_C(x) x##UL
#else
#define INT64_C(x) x##LL
#define UINT64_C(x) x##ULL
#endif
#endif
#endif
/**@}*/
/**\name C standard macros */
#ifndef NULL
#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void *) 0)
#endif
#endif
/** BME680 General config */
#define BME680_POLL_PERIOD_MS UINT8_C(10)
/** BME680 I2C addresses */
#define BME680_I2C_ADDR_PRIMARY UINT8_C(0x76)
#define BME680_I2C_ADDR_SECONDARY UINT8_C(0x77)
/** BME680 unique chip identifier */
#define BME680_CHIP_ID UINT8_C(0x61)
/** BME680 coefficients related defines */
#define BME680_COEFF_SIZE UINT8_C(0x41)
#define BME680_COEFF_ADDR1_LEN UINT8_C(25)
#define BME680_COEFF_ADDR2_LEN UINT8_C(16)
/** BME680 field_x related defines */
#define BME680_FIELD_LENGTH UINT8_C(15)
#define BME680_FIELD_ADDR_OFFSET UINT8_C(17)
/** Soft reset command */
#define BME680_SOFT_RESET_CMD UINT8_C(0xb6)
/** Error code definitions */
#define BME680_OK INT8_C(0)
/* Errors */
#define BME680_E_NULL_PTR INT8_C(-1)
#define BME680_E_COM_FAIL INT8_C(-2)
#define BME680_E_DEV_NOT_FOUND INT8_C(-3)
#define BME680_E_INVALID_LENGTH INT8_C(-4)
/* Warnings */
#define BME680_W_DEFINE_PWR_MODE INT8_C(1)
#define BME680_W_NO_NEW_DATA INT8_C(2)
/* Info's */
#define BME680_I_MIN_CORRECTION UINT8_C(1)
#define BME680_I_MAX_CORRECTION UINT8_C(2)
/** Register map */
/** Other coefficient's address */
#define BME680_ADDR_RES_HEAT_VAL_ADDR UINT8_C(0x00)
#define BME680_ADDR_RES_HEAT_RANGE_ADDR UINT8_C(0x02)
#define BME680_ADDR_RANGE_SW_ERR_ADDR UINT8_C(0x04)
#define BME680_ADDR_SENS_CONF_START UINT8_C(0x5A)
#define BME680_ADDR_GAS_CONF_START UINT8_C(0x64)
/** Field settings */
#define BME680_FIELD0_ADDR UINT8_C(0x1d)
/** Heater settings */
#define BME680_RES_HEAT0_ADDR UINT8_C(0x5a)
#define BME680_GAS_WAIT0_ADDR UINT8_C(0x64)
/** Sensor configuration registers */
#define BME680_CONF_HEAT_CTRL_ADDR UINT8_C(0x70)
#define BME680_CONF_ODR_RUN_GAS_NBC_ADDR UINT8_C(0x71)
#define BME680_CONF_OS_H_ADDR UINT8_C(0x72)
#define BME680_MEM_PAGE_ADDR UINT8_C(0xf3)
#define BME680_CONF_T_P_MODE_ADDR UINT8_C(0x74)
#define BME680_CONF_ODR_FILT_ADDR UINT8_C(0x75)
/** Coefficient's address */
#define BME680_COEFF_ADDR1 UINT8_C(0x89)
#define BME680_COEFF_ADDR2 UINT8_C(0xe1)
/** Chip identifier */
#define BME680_CHIP_ID_ADDR UINT8_C(0xd0)
/** Soft reset register */
#define BME680_SOFT_RESET_ADDR UINT8_C(0xe0)
/** Heater control settings */
#define BME680_ENABLE_HEATER UINT8_C(0x00)
#define BME680_DISABLE_HEATER UINT8_C(0x08)
/** Gas measurement settings */
#define BME680_DISABLE_GAS_MEAS UINT8_C(0x00)
#define BME680_ENABLE_GAS_MEAS UINT8_C(0x01)
/** Over-sampling settings */
#define BME680_OS_NONE UINT8_C(0)
#define BME680_OS_1X UINT8_C(1)
#define BME680_OS_2X UINT8_C(2)
#define BME680_OS_4X UINT8_C(3)
#define BME680_OS_8X UINT8_C(4)
#define BME680_OS_16X UINT8_C(5)
/** IIR filter settings */
#define BME680_FILTER_SIZE_0 UINT8_C(0)
#define BME680_FILTER_SIZE_1 UINT8_C(1)
#define BME680_FILTER_SIZE_3 UINT8_C(2)
#define BME680_FILTER_SIZE_7 UINT8_C(3)
#define BME680_FILTER_SIZE_15 UINT8_C(4)
#define BME680_FILTER_SIZE_31 UINT8_C(5)
#define BME680_FILTER_SIZE_63 UINT8_C(6)
#define BME680_FILTER_SIZE_127 UINT8_C(7)
/** Power mode settings */
#define BME680_SLEEP_MODE UINT8_C(0)
#define BME680_FORCED_MODE UINT8_C(1)
/** Delay related macro declaration */
#define BME680_RESET_PERIOD UINT32_C(10)
/** SPI memory page settings */
#define BME680_MEM_PAGE0 UINT8_C(0x10)
#define BME680_MEM_PAGE1 UINT8_C(0x00)
/** Ambient humidity shift value for compensation */
#define BME680_HUM_REG_SHIFT_VAL UINT8_C(4)
/** Run gas enable and disable settings */
#define BME680_RUN_GAS_DISABLE UINT8_C(0)
#define BME680_RUN_GAS_ENABLE UINT8_C(1)
/** Buffer length macro declaration */
#define BME680_TMP_BUFFER_LENGTH UINT8_C(40)
#define BME680_REG_BUFFER_LENGTH UINT8_C(6)
#define BME680_FIELD_DATA_LENGTH UINT8_C(3)
#define BME680_GAS_REG_BUF_LENGTH UINT8_C(20)
#define BME680_GAS_HEATER_PROF_LEN_MAX UINT8_C(10)
/** Settings selector */
#define BME680_OST_SEL UINT16_C(1)
#define BME680_OSP_SEL UINT16_C(2)
#define BME680_OSH_SEL UINT16_C(4)
#define BME680_GAS_MEAS_SEL UINT16_C(8)
#define BME680_FILTER_SEL UINT16_C(16)
#define BME680_HCNTRL_SEL UINT16_C(32)
#define BME680_RUN_GAS_SEL UINT16_C(64)
#define BME680_NBCONV_SEL UINT16_C(128)
#define BME680_GAS_SENSOR_SEL UINT16_C(BME680_GAS_MEAS_SEL | BME680_RUN_GAS_SEL | BME680_NBCONV_SEL)
/** Number of conversion settings*/
#define BME680_NBCONV_MIN UINT8_C(0)
#define BME680_NBCONV_MAX UINT8_C(10)
/** Mask definitions */
#define BME680_GAS_MEAS_MSK UINT8_C(0x30)
#define BME680_NBCONV_MSK UINT8_C(0X0F)
#define BME680_FILTER_MSK UINT8_C(0X1C)
#define BME680_OST_MSK UINT8_C(0XE0)
#define BME680_OSP_MSK UINT8_C(0X1C)
#define BME680_OSH_MSK UINT8_C(0X07)
#define BME680_HCTRL_MSK UINT8_C(0x08)
#define BME680_RUN_GAS_MSK UINT8_C(0x10)
#define BME680_MODE_MSK UINT8_C(0x03)
#define BME680_RHRANGE_MSK UINT8_C(0x30)
#define BME680_RSERROR_MSK UINT8_C(0xf0)
#define BME680_NEW_DATA_MSK UINT8_C(0x80)
#define BME680_GAS_INDEX_MSK UINT8_C(0x0f)
#define BME680_GAS_RANGE_MSK UINT8_C(0x0f)
#define BME680_GASM_VALID_MSK UINT8_C(0x20)
#define BME680_HEAT_STAB_MSK UINT8_C(0x10)
#define BME680_MEM_PAGE_MSK UINT8_C(0x10)
#define BME680_SPI_RD_MSK UINT8_C(0x80)
#define BME680_SPI_WR_MSK UINT8_C(0x7f)
#define BME680_BIT_H1_DATA_MSK UINT8_C(0x0F)
/** Bit position definitions for sensor settings */
#define BME680_GAS_MEAS_POS UINT8_C(4)
#define BME680_FILTER_POS UINT8_C(2)
#define BME680_OST_POS UINT8_C(5)
#define BME680_OSP_POS UINT8_C(2)
#define BME680_RUN_GAS_POS UINT8_C(4)
/** Array Index to Field data mapping for Calibration Data*/
#define BME680_T2_LSB_REG (1)
#define BME680_T2_MSB_REG (2)
#define BME680_T3_REG (3)
#define BME680_P1_LSB_REG (5)
#define BME680_P1_MSB_REG (6)
#define BME680_P2_LSB_REG (7)
#define BME680_P2_MSB_REG (8)
#define BME680_P3_REG (9)
#define BME680_P4_LSB_REG (11)
#define BME680_P4_MSB_REG (12)
#define BME680_P5_LSB_REG (13)
#define BME680_P5_MSB_REG (14)
#define BME680_P7_REG (15)
#define BME680_P6_REG (16)
#define BME680_P8_LSB_REG (19)
#define BME680_P8_MSB_REG (20)
#define BME680_P9_LSB_REG (21)
#define BME680_P9_MSB_REG (22)
#define BME680_P10_REG (23)
#define BME680_H2_MSB_REG (25)
#define BME680_H2_LSB_REG (26)
#define BME680_H1_LSB_REG (26)
#define BME680_H1_MSB_REG (27)
#define BME680_H3_REG (28)
#define BME680_H4_REG (29)
#define BME680_H5_REG (30)
#define BME680_H6_REG (31)
#define BME680_H7_REG (32)
#define BME680_T1_LSB_REG (33)
#define BME680_T1_MSB_REG (34)
#define BME680_GH2_LSB_REG (35)
#define BME680_GH2_MSB_REG (36)
#define BME680_GH1_REG (37)
#define BME680_GH3_REG (38)
/** BME680 register buffer index settings*/
#define BME680_REG_FILTER_INDEX UINT8_C(5)
#define BME680_REG_TEMP_INDEX UINT8_C(4)
#define BME680_REG_PRES_INDEX UINT8_C(4)
#define BME680_REG_HUM_INDEX UINT8_C(2)
#define BME680_REG_NBCONV_INDEX UINT8_C(1)
#define BME680_REG_RUN_GAS_INDEX UINT8_C(1)
#define BME680_REG_HCTRL_INDEX UINT8_C(0)
/** Macro to combine two 8 bit data's to form a 16 bit data */
#define BME680_CONCAT_BYTES(msb, lsb) (((uint16_t)msb << 8) | (uint16_t)lsb)
/** Macro to SET and GET BITS of a register */
#define BME680_SET_BITS(reg_data, bitname, data) \
((reg_data & ~(bitname##_MSK)) | \
((data << bitname##_POS) & bitname##_MSK))
#define BME680_GET_BITS(reg_data, bitname) ((reg_data & (bitname##_MSK)) >> \
(bitname##_POS))
/** Macro variant to handle the bitname position if it is zero */
#define BME680_SET_BITS_POS_0(reg_data, bitname, data) \
((reg_data & ~(bitname##_MSK)) | \
(data & bitname##_MSK))
#define BME680_GET_BITS_POS_0(reg_data, bitname) (reg_data & (bitname##_MSK))
/** Type definitions */
/*
* Generic communication function pointer
* @param[in] dev_id: Place holder to store the id of the device structure
* Can be used to store the index of the Chip select or
* I2C address of the device.
* @param[in] reg_addr: Used to select the register the where data needs to
* be read from or written to.
* @param[in/out] reg_data: Data array to read/write
* @param[in] len: Length of the data array
*/
typedef int8_t (*bme680_com_fptr_t)(uint8_t dev_id, uint8_t reg_addr, uint8_t *data, uint16_t len);
/*
* Delay function pointer
* @param[in] period: Time period in milliseconds
*/
typedef void (*bme680_delay_fptr_t)(uint32_t period);
/*!
* @brief Interface selection Enumerations
*/
enum bme680_intf {
/*! SPI interface */
BME680_SPI_INTF,
/*! I2C interface */
BME680_I2C_INTF
};
/* structure definitions */
/*!
* @brief Sensor field data structure
*/
struct bme680_field_data {
/*! Contains new_data, gasm_valid & heat_stab */
uint8_t status;
/*! The index of the heater profile used */
uint8_t gas_index;
/*! Measurement index to track order */
uint8_t meas_index;
/*! Temperature in degree celsius x100 */
int16_t temperature;
/*! Pressure in Pascal */
uint32_t pressure;
/*! Humidity in % relative humidity x1000 */
uint32_t humidity;
/*! Gas resistance in Ohms */
uint32_t gas_resistance;
};
/*!
* @brief Structure to hold the Calibration data
*/
struct bme680_calib_data {
/*! Variable to store calibrated humidity data */
uint16_t par_h1;
/*! Variable to store calibrated humidity data */
uint16_t par_h2;
/*! Variable to store calibrated humidity data */
int8_t par_h3;
/*! Variable to store calibrated humidity data */
int8_t par_h4;
/*! Variable to store calibrated humidity data */
int8_t par_h5;
/*! Variable to store calibrated humidity data */
uint8_t par_h6;
/*! Variable to store calibrated humidity data */
int8_t par_h7;
/*! Variable to store calibrated gas data */
int8_t par_gh1;
/*! Variable to store calibrated gas data */
int16_t par_gh2;
/*! Variable to store calibrated gas data */
int8_t par_gh3;
/*! Variable to store calibrated temperature data */
uint16_t par_t1;
/*! Variable to store calibrated temperature data */
int16_t par_t2;
/*! Variable to store calibrated temperature data */
int8_t par_t3;
/*! Variable to store calibrated pressure data */
uint16_t par_p1;
/*! Variable to store calibrated pressure data */
int16_t par_p2;
/*! Variable to store calibrated pressure data */
int8_t par_p3;
/*! Variable to store calibrated pressure data */
int16_t par_p4;
/*! Variable to store calibrated pressure data */
int16_t par_p5;
/*! Variable to store calibrated pressure data */
int8_t par_p6;
/*! Variable to store calibrated pressure data */
int8_t par_p7;
/*! Variable to store calibrated pressure data */
int16_t par_p8;
/*! Variable to store calibrated pressure data */
int16_t par_p9;
/*! Variable to store calibrated pressure data */
uint8_t par_p10;
/*! Variable to store t_fine size */
int32_t t_fine;
/*! Variable to store heater resistance range */
uint8_t res_heat_range;
/*! Variable to store heater resistance value */
int8_t res_heat_val;
/*! Variable to store error range */
int8_t range_sw_err;
};
/*!
* @brief BME680 sensor settings structure which comprises of ODR,
* over-sampling and filter settings.
*/
struct bme680_tph_sett {
/*! Humidity oversampling */
uint8_t os_hum;
/*! Temperature oversampling */
uint8_t os_temp;
/*! Pressure oversampling */
uint8_t os_pres;
/*! Filter coefficient */
uint8_t filter;
};
/*!
* @brief BME680 gas sensor which comprises of gas settings
* and status parameters
*/
struct bme680_gas_sett {
/*! Variable to store nb conversion */
uint8_t nb_conv;
/*! Variable to store heater control */
uint8_t heatr_ctrl;
/*! Run gas enable value */
uint8_t run_gas;
/*! Pointer to store heater temperature */
uint16_t heatr_temp;
/*! Pointer to store duration profile */
uint16_t heatr_dur;
};
/*!
* @brief BME680 device structure
*/
struct bme680_dev {
/*! Chip Id */
uint8_t chip_id;
/*! Device Id */
uint8_t dev_id;
/*! SPI/I2C interface */
enum bme680_intf intf;
/*! Memory page used */
uint8_t mem_page;
/*! Ambient temperature in Degree C*/
int8_t amb_temp;
/*! Sensor calibration data */
struct bme680_calib_data calib;
/*! Sensor settings */
struct bme680_tph_sett tph_sett;
/*! Gas Sensor settings */
struct bme680_gas_sett gas_sett;
/*! Sensor power modes */
uint8_t power_mode;
/*! New sensor fields */
uint8_t new_fields;
/*! Store the info messages */
uint8_t info_msg;
/*! Burst read structure */
bme680_com_fptr_t read;
/*! Burst write structure */
bme680_com_fptr_t write;
/*! Delay in ms */
bme680_delay_fptr_t delay_ms;
/*! Communication function result */
int8_t com_rslt;
};
#endif /* BME680_DEFS_H_ */
/** @}*/
/** @}*/
...@@ -63,28 +63,6 @@ static int bmp085_setup(lua_State* L) { ...@@ -63,28 +63,6 @@ static int bmp085_setup(lua_State* L) {
return 0; return 0;
} }
static int bmp085_init(lua_State* L) {
uint32_t sda;
uint32_t scl;
platform_print_deprecation_note("bmp085.init() is replaced by bmp085.setup()", "in the next version");
if (!lua_isnumber(L, 1) || !lua_isnumber(L, 2)) {
return luaL_error(L, "wrong arg range");
}
sda = luaL_checkinteger(L, 1);
scl = luaL_checkinteger(L, 2);
if (scl == 0 || sda == 0) {
return luaL_error(L, "no i2c for D0");
}
platform_i2c_setup(bmp085_i2c_id, sda, scl, PLATFORM_I2C_SPEED_SLOW);
return bmp085_setup(L);
}
static uint32_t bmp085_temperature_raw_b5(void) { static uint32_t bmp085_temperature_raw_b5(void) {
int16_t t, X1, X2; int16_t t, X1, X2;
...@@ -196,8 +174,6 @@ static const LUA_REG_TYPE bmp085_map[] = { ...@@ -196,8 +174,6 @@ static const LUA_REG_TYPE bmp085_map[] = {
{ LSTRKEY( "pressure" ), LFUNCVAL( bmp085_lua_pressure )}, { LSTRKEY( "pressure" ), LFUNCVAL( bmp085_lua_pressure )},
{ LSTRKEY( "pressure_raw" ), LFUNCVAL( bmp085_lua_pressure_raw )}, { LSTRKEY( "pressure_raw" ), LFUNCVAL( bmp085_lua_pressure_raw )},
{ LSTRKEY( "setup" ), LFUNCVAL( bmp085_setup )}, { LSTRKEY( "setup" ), LFUNCVAL( bmp085_setup )},
// init() is deprecated
{ LSTRKEY( "init" ), LFUNCVAL( bmp085_init )},
{ LNILKEY, LNILVAL} { LNILKEY, LNILVAL}
}; };
......
#include "module.h"
#include "lauxlib.h"
#include "lmem.h"
#include "platform.h"
#include "c_stdlib.h"
#include "c_math.h"
#include "c_string.h"
#include "user_interface.h"
#include "osapi.h"
#include "color_utils.h"
#define min(a,b) ((a) < (b) ? (a) : (b))
#define max(a,b) ((a) > (b) ? (a) : (b))
#define abs(a) ((a) > 0 ? (a) : (0-a))
#define min3(a,b, c) min((a), min((b), (c)))
#define max3(a,b, c) max((a), max((b), (c)))
#define CANARY_VALUE 0x37383132
// convert hsv to grb value
uint32_t hsv2grb(uint16_t hue, uint8_t sat, uint8_t val)
{
uint16_t H_accent = (hue % 360) / 60;
uint16_t bottom = ((255 - sat) * val)>>8;
uint16_t top = val;
uint8_t rising = ((top-bottom) *(hue%60 ) ) / 60 + bottom;
uint8_t falling = ((top-bottom) *(60-hue%60) ) / 60 + bottom;
uint8_t r;
uint8_t g;
uint8_t b;
switch(H_accent) {
case 0:
r = top;
g = rising;
b = bottom;
break;
case 1:
r = falling;
g = top;
b = bottom;
break;
case 2:
r = bottom;
g = top;
b = rising;
break;
case 3:
r = bottom;
g = falling;
b = top;
break;
case 4:
r = rising;
g = bottom;
b = top;
break;
case 5:
r = top;
g = bottom;
b = falling;
break;
}
uint32_t result = (g << 16) | (r << 8) | b;
return result;
}
// convert hsv to grbw value
uint32_t hsv2grbw(uint16_t hue, uint8_t sat, uint8_t val) {
uint32_t grb = hsv2grb(hue, sat, val);
uint8_t g = ((grb & 0x00FF0000) >> 16);
uint8_t r = ((grb & 0x0000FF00) >> 8);
uint8_t b = (grb & 0x000000FF);
// calculate white component
uint8_t w = min3(g, r, b);
g = g - w;
r = r - w;
b = b - w;
uint32_t grbw = (g << 24) | (r << 16) | (b << 8) | w;
return grbw;
}
// convert grb to hsv value
uint32_t grb2hsv(uint8_t g, uint8_t r, uint8_t b) {
uint8_t m = min3(r, g, b);
uint8_t M = max3(r, g, b);
uint8_t delta = M - m;
int hue = 0;
int saturation = 0;
int value = 0;
if(delta == 0) {
/* Achromatic case (i.e. grayscale) */
hue = -1; /* undefined */
saturation = 0;
} else {
int h;
if(r == M)
h = ((g-b)*60) / delta;
else if(g == M)
h = ((b-r)*60) / delta + 120;
else /*if(b == M)*/
h = ((r-g)*60) / delta + 240;
if(h < 0)
h += 360;
hue = h;
/* The constatnt 8 is tuned to statistically cause as little
* tolerated mismatches as possible in RGB -> HSV -> RGB conversion.
* (See the unit test at the bottom of this file.)
*/
saturation = (256*delta-8) / M;
}
value = M;
uint32_t result = (hue << 16) | (saturation << 8) | value;
return result;
}
/*
* Put a value 0 to 360 in to get a color value.
* The colours are a transition r -> g -> b -> back to r
* Inspired by the Adafruit examples.
*/
uint32_t color_wheel(uint16_t pos) {
return hsv2grb(pos, 255, 255);
}
// convert hsv to grb value
static int cu_hsv2grb(lua_State *L) {
const int hue = luaL_checkint(L, 1);
const int sat = luaL_checkint(L, 2);
const int val = luaL_checkint(L, 3);
luaL_argcheck(L, hue >= 0 && hue <= 360, 1, "should be a 0-360");
luaL_argcheck(L, sat >= 0 && sat <= 255, 2, "should be 0-255");
luaL_argcheck(L, val >= 0 && val <= 255, 3, "should be 0-255");
// convert to grb
uint32_t tmp_color = hsv2grb(hue, sat, val);
// return
lua_pushnumber(L, (tmp_color & 0x00FF0000) >> 16);
lua_pushnumber(L, (tmp_color & 0x0000FF00) >> 8);
lua_pushnumber(L, (tmp_color & 0x000000FF));
return 3;
}
// convert hsv to grbw value
static int cu_hsv2grbw(lua_State *L) {
const int hue = luaL_checkint(L, 1);
const int sat = luaL_checkint(L, 2);
const int val = luaL_checkint(L, 3);
luaL_argcheck(L, hue >= 0 && hue <= 360, 1, "should be a 0-360");
luaL_argcheck(L, sat >= 0 && sat <= 255, 2, "should be 0-255");
luaL_argcheck(L, val >= 0 && val <= 255, 3, "should be 0-255");
// convert to grbw
uint32_t tmp_color = hsv2grbw(hue, sat, val);
// return g, r, b, w
lua_pushnumber(L, (tmp_color & 0xFF000000) >> 24);
lua_pushnumber(L, (tmp_color & 0x00FF0000) >> 16);
lua_pushnumber(L, (tmp_color & 0x0000FF00) >> 8);
lua_pushnumber(L, (tmp_color & 0x000000FF));
return 4;
}
// create a color wheel value
static int cu_color_wheel(lua_State *L) {
const int wheel_index = luaL_checkint(L, 1);
luaL_argcheck(L, wheel_index >= 0 && wheel_index <= 360, 1, "should be a 0-360");
uint32_t color = color_wheel(wheel_index);
uint8_t r = (color & 0x00FF0000) >> 16;
uint8_t g = (color & 0x0000FF00) >> 8;
uint8_t b = (color & 0x000000FF) >> 0;
// return
lua_pushnumber(L, g);
lua_pushnumber(L, r);
lua_pushnumber(L, b);
return 3;
}
// convert grb values to hsv
static int cu_grb2hsv(lua_State *L) {
const int g = luaL_checkint(L, 1);
const int r = luaL_checkint(L, 2);
const int b = luaL_checkint(L, 3);
luaL_argcheck(L, g == r && g == b, 1, "greyscale value cannot be converted to hsv");
uint32_t hsv = grb2hsv(g, r, b);
uint16_t h = (hsv & 0xFFFF0000) >> 16;
uint8_t s = (hsv & 0x0000FF00) >> 8;
uint8_t v = (hsv & 0x000000FF) >> 0;
// return
lua_pushnumber(L, h);
lua_pushnumber(L, s);
lua_pushnumber(L, v);
return 3;
}
static const LUA_REG_TYPE color_utils_map[] =
{
{ LSTRKEY( "hsv2grb" ), LFUNCVAL( cu_hsv2grb )},
{ LSTRKEY( "hsv2grbw" ), LFUNCVAL( cu_hsv2grbw )},
{ LSTRKEY( "colorWheel" ), LFUNCVAL( cu_color_wheel )},
{ LSTRKEY( "grb2hsv" ), LFUNCVAL( cu_grb2hsv )},
{ LNILKEY, LNILVAL}
};
NODEMCU_MODULE(COLOR_UTILS, "color_utils", color_utils_map, NULL);
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment