Unverified Commit 11592951 authored by Arnim Läuger's avatar Arnim Läuger Committed by GitHub
Browse files

Merge pull request #2582 from nodemcu/dev

Next master drop
parents 4095c408 61433c44
......@@ -44,7 +44,7 @@ INCLUDES += -I ../libc
INCLUDES += -I ../coap
INCLUDES += -I ../mqtt
INCLUDES += -I ../u8g2lib/u8g2/src/clib
INCLUDES += -I ../ucglib
INCLUDES += -I ../ucglib/ucg/src/clib
INCLUDES += -I ../lua
INCLUDES += -I ../pcm
INCLUDES += -I ../platform
......
......@@ -32,18 +32,23 @@ static size_t cronent_count = 0;
static uint64_t lcron_parsepart(lua_State *L, char *str, char **end, uint8_t min, uint8_t max) {
uint64_t res = 0;
/* Gobble whitespace before potential stars; no strtol on that path */
while (*str != '\0' && (*str == ' ' || *str == '\t')) {
str++;
}
if (str[0] == '*') {
uint32_t each = 1;
*end = str + 1;
if (str[1] == '/') {
each = strtol(str + 2, end, 10);
if (end != 0)
if (each == 0 || each >= max - min) {
return luaL_error(L, "invalid spec (each %d)", each);
}
}
for (int i = 0; i <= (max - min); i++) {
if (((min + i) % each) == 0) res |= (uint64_t)1 << i;
if ((i % each) == 0) res |= (uint64_t)1 << i;
}
} else {
uint32_t val;
......@@ -63,14 +68,17 @@ static uint64_t lcron_parsepart(lua_State *L, char *str, char **end, uint8_t min
static int lcron_parsedesc(lua_State *L, char *str, struct cronent_desc *desc) {
char *s = str;
desc->min = lcron_parsepart(L, s, &s, 0, 59);
if (*s != ' ') return luaL_error(L, "invalid spec (separator @%d)", s - str);
if (*s != ' ' && *s != '\t') return luaL_error(L, "invalid spec (separator @%d)", s - str);
desc->hour = lcron_parsepart(L, s + 1, &s, 0, 23);
if (*s != ' ') return luaL_error(L, "invalid spec (separator @%d)", s - str);
if (*s != ' ' && *s != '\t') return luaL_error(L, "invalid spec (separator @%d)", s - str);
desc->dom = lcron_parsepart(L, s + 1, &s, 1, 31);
if (*s != ' ') return luaL_error(L, "invalid spec (separator @%d)", s - str);
if (*s != ' ' && *s != '\t') return luaL_error(L, "invalid spec (separator @%d)", s - str);
desc->mon = lcron_parsepart(L, s + 1, &s, 1, 12);
if (*s != ' ') return luaL_error(L, "invalid spec (separator @%d)", s - str);
if (*s != ' ' && *s != '\t') return luaL_error(L, "invalid spec (separator @%d)", s - str);
desc->dow = lcron_parsepart(L, s + 1, &s, 0, 6);
while (*s != '\0' && (*s == ' ' || *s == '\t')) {
s++;
}
if (*s != 0) return luaL_error(L, "invalid spec (trailing @%d)", s - str);
return 0;
}
......@@ -78,6 +86,7 @@ static int lcron_parsedesc(lua_State *L, char *str, struct cronent_desc *desc) {
static int lcron_create(lua_State *L) {
// Check arguments
char *strdesc = (char*)luaL_checkstring(L, 1);
void *newlist;
luaL_checkanyfunction(L, 2);
// Parse description
struct cronent_desc desc;
......@@ -93,8 +102,12 @@ static int lcron_create(lua_State *L) {
// Set entry
ud->desc = desc;
// Store entry
newlist = os_realloc(cronent_list, sizeof(int) * (cronent_count + 1));
if (newlist == NULL) {
return luaL_error(L, "out of memory");
}
lua_pushvalue(L, -1);
cronent_list = os_realloc(cronent_list, sizeof(int) * (cronent_count + 1));
cronent_list = newlist;
cronent_list[cronent_count++] = luaL_ref(L, LUA_REGISTRYINDEX);
return 1;
}
......@@ -120,8 +133,13 @@ static int lcron_schedule(lua_State *L) {
ud->desc = desc;
size_t i = lcron_findindex(L, ud);
if (i == -1) {
void *newlist;
newlist = os_realloc(cronent_list, sizeof(int) * (cronent_count + 1));
if (newlist == NULL) {
return luaL_error(L, "out of memory");
}
cronent_list = newlist;
lua_pushvalue(L, 1);
cronent_list = os_realloc(cronent_list, sizeof(int) * (cronent_count + 1));
cronent_list[cronent_count++] = lua_ref(L, LUA_REGISTRYINDEX);
}
return 0;
......
......@@ -67,6 +67,9 @@ static int ds18b20_lua_readoutdone(void);
// Setup onewire bus for DS18B20 temperature sensors
// Lua: ds18b20.setup(OW_BUS_PIN)
static int ds18b20_lua_setup(lua_State *L) {
platform_print_deprecation_note("ds18b20 C module superseded by Lua implementation", "soon");
// check ow bus pin value
if (!lua_isnumber(L, 1) || lua_isnumber(L, 1) == 0) {
return luaL_error(L, "wrong 1-wire pin");
......
......@@ -587,7 +587,7 @@ static int file_mount( lua_State *L )
if (vol->vol = vfs_mount( ldrv, num )) {
/* set its metatable */
luaL_getmetatable(L, "vfs.vol");
luaL_getmetatable(L, "file.vol");
lua_setmetatable(L, -2);
return 1;
} else {
......
......@@ -17,7 +17,7 @@
#include "user_interface.h"
#define MQTT_BUF_SIZE 1024
#define MQTT_BUF_SIZE 1460
#define MQTT_DEFAULT_KEEPALIVE 60
#define MQTT_MAX_CLIENT_LEN 64
#define MQTT_MAX_USER_LEN 64
......@@ -46,17 +46,32 @@ typedef struct mqtt_event_data_t
#define RECONNECT_POSSIBLE 1
#define RECONNECT_ON 2
typedef enum {
MQTT_RECV_NORMAL,
MQTT_RECV_BUFFERING_SHORT,
MQTT_RECV_BUFFERING,
MQTT_RECV_SKIPPING,
} tReceiveState;
typedef struct mqtt_state_t
{
uint16_t port;
uint8_t auto_reconnect; // 0 is not auto_reconnect. 1 is auto reconnect, but never connected. 2 is auto reconnect, but once connected
mqtt_connect_info_t* connect_info;
uint16_t message_length;
uint16_t message_length_read;
mqtt_connection_t mqtt_connection;
msg_queue_t* pending_msg_q;
uint8_t * recv_buffer; // heap buffer for multi-packet rx
uint8_t * recv_buffer_wp; // write pointer in multi-packet rx
union {
uint16_t recv_buffer_size; // size of recv_buffer
uint32_t recv_buffer_skip; // number of bytes left to skip, in skipping state
};
tReceiveState recv_buffer_state;
} mqtt_state_t;
typedef struct lmqtt_userdata
{
struct espconn *pesp_conn;
......@@ -65,6 +80,7 @@ typedef struct lmqtt_userdata
int cb_connect_fail_ref;
int cb_disconnect_ref;
int cb_message_ref;
int cb_overflow_ref;
int cb_suback_ref;
int cb_unsuback_ref;
int cb_puback_ref;
......@@ -81,6 +97,9 @@ typedef struct lmqtt_userdata
tConnState connState;
}lmqtt_userdata;
// How large MQTT messages to accept by default
#define DEFAULT_MAX_MESSAGE_LENGTH 1024
static sint8 socket_connect(struct espconn *pesp_conn);
static void mqtt_socket_reconnected(void *arg, sint8_t err);
static void mqtt_socket_connected(void *arg);
......@@ -110,6 +129,13 @@ static void mqtt_socket_disconnected(void *arg) // tcp only
}
}
if(mud->mqtt_state.recv_buffer) {
c_free(mud->mqtt_state.recv_buffer);
mud->mqtt_state.recv_buffer = NULL;
}
mud->mqtt_state.recv_buffer_size = 0;
mud->mqtt_state.recv_buffer_state = MQTT_RECV_NORMAL;
if(mud->mqtt_state.auto_reconnect == RECONNECT_ON) {
mud->pesp_conn->reverse = mud;
mud->pesp_conn->type = ESPCONN_TCP;
......@@ -178,9 +204,9 @@ static void mqtt_socket_reconnected(void *arg, sint8_t err)
NODE_DBG("leave mqtt_socket_reconnected.\n");
}
static void deliver_publish(lmqtt_userdata * mud, uint8_t* message, int length)
static void deliver_publish(lmqtt_userdata * mud, uint8_t* message, uint16_t length, uint8_t is_overflow)
{
NODE_DBG("enter deliver_publish.\n");
NODE_DBG("enter deliver_publish (len=%d, overflow=%d).\n", length, is_overflow);
if(mud == NULL)
return;
mqtt_event_data_t event_data;
......@@ -191,13 +217,15 @@ static void deliver_publish(lmqtt_userdata * mud, uint8_t* message, int length)
event_data.data_length = length;
event_data.data = mqtt_get_publish_data(message, &event_data.data_length);
if(mud->cb_message_ref == LUA_NOREF)
int cb_ref = !is_overflow ? mud->cb_message_ref : mud->cb_overflow_ref;
if(cb_ref == LUA_NOREF)
return;
if(mud->self_ref == LUA_NOREF)
return;
lua_State *L = lua_getstate();
if(event_data.topic && (event_data.topic_length > 0)){
lua_rawgeti(L, LUA_REGISTRYINDEX, mud->cb_message_ref);
lua_rawgeti(L, LUA_REGISTRYINDEX, cb_ref);
lua_rawgeti(L, LUA_REGISTRYINDEX, mud->self_ref); // pass the userdata to callback func in lua
lua_pushlstring(L, event_data.topic, event_data.topic_length);
} else {
......@@ -265,14 +293,15 @@ static sint8 mqtt_send_if_possible(struct espconn *pesp_conn)
static void mqtt_socket_received(void *arg, char *pdata, unsigned short len)
{
NODE_DBG("enter mqtt_socket_received.\n");
NODE_DBG("enter mqtt_socket_received (rxlen=%u).\n", len);
uint8_t msg_type;
uint8_t msg_qos;
uint16_t msg_id;
int length = (int)len;
// uint8_t in_buffer[MQTT_BUF_SIZE];
uint8_t *in_buffer = (uint8_t *)pdata;
uint16_t in_buffer_length = len;
uint8_t *continuation_buffer = NULL;
uint8_t *temp_pdata = NULL;
struct espconn *pesp_conn = arg;
if(pesp_conn == NULL)
......@@ -281,11 +310,109 @@ static void mqtt_socket_received(void *arg, char *pdata, unsigned short len)
if(mud == NULL)
return;
READPACKET:
if(length > MQTT_BUF_SIZE || length <= 0)
switch(mud->mqtt_state.recv_buffer_state) {
case MQTT_RECV_NORMAL:
// No previous buffer.
break;
case MQTT_RECV_BUFFERING_SHORT:
// Last buffer had so few byte that we could not determine message length.
// Store in a local heap buffer and operate on this, as if was the regular pdata buffer.
// Avoids having to repeat message size/overflow logic.
temp_pdata = c_zalloc(mud->mqtt_state.recv_buffer_size + len);
if(temp_pdata == NULL) {
NODE_DBG("MQTT[buffering-short]: Failed to allocate %u bytes, disconnecting...\n", mud->mqtt_state.recv_buffer_size + len);
#ifdef CLIENT_SSL_ENABLE
if (mud->secure) {
espconn_secure_disconnect(pesp_conn);
} else
#endif
{
espconn_disconnect(pesp_conn);
}
return;
}
NODE_DBG("MQTT[buffering-short]: Continuing with %u + %u bytes\n", mud->mqtt_state.recv_buffer_size, len);
memcpy(temp_pdata, mud->mqtt_state.recv_buffer, mud->mqtt_state.recv_buffer_size);
memcpy(temp_pdata + mud->mqtt_state.recv_buffer_size, pdata, len);
c_free(mud->mqtt_state.recv_buffer);
mud->mqtt_state.recv_buffer = NULL;
mud->mqtt_state.recv_buffer_state = MQTT_RECV_NORMAL;
in_buffer = temp_pdata;
in_buffer_length = mud->mqtt_state.recv_buffer_size + len;
break;
case MQTT_RECV_BUFFERING: {
// safe cast: we never allow longer buffer.
uint16_t current_length = (uint16_t) (mud->mqtt_state.recv_buffer_wp - mud->mqtt_state.recv_buffer);
NODE_DBG("MQTT[buffering]: appending %u bytes to previous recv buffer (%u out of wanted %u)\n",
in_buffer_length,
current_length,
mud->mqtt_state.recv_buffer_size);
// Copy from rx buffer to heap buffer. Smallest of [remainder of pending message] and [all of buffer]
uint16_t copy_length = LWIP_MIN(mud->mqtt_state.recv_buffer_size - current_length, in_buffer_length);
memcpy(mud->mqtt_state.recv_buffer_wp, pdata, copy_length);
mud->mqtt_state.recv_buffer_wp += copy_length;
// c_memcpy(in_buffer, pdata, length);
in_buffer_length = (uint16_t) (mud->mqtt_state.recv_buffer_wp - mud->mqtt_state.recv_buffer);
if (in_buffer_length < mud->mqtt_state.recv_buffer_size) {
NODE_DBG("MQTT[buffering]: need %u more bytes, waiting for next rx.\n",
mud->mqtt_state.recv_buffer_size - in_buffer_length
);
goto RX_PACKET_FINISHED;
}
NODE_DBG("MQTT[buffering]: Full message received (%u). remainding bytes=%u\n",
mud->mqtt_state.recv_buffer_size,
len - copy_length);
// Point continuation_buffer to any additional data in pdata.
// May become 0 bytes, but used to trigger free!
continuation_buffer = pdata + copy_length;
len -= copy_length; // borrow len instead of having another variable..
in_buffer = mud->mqtt_state.recv_buffer;
// in_buffer_length was set above
mud->mqtt_state.recv_buffer_state = MQTT_RECV_NORMAL;
break;
}
case MQTT_RECV_SKIPPING:
// Last rx had a message which was too large to process, skip it.
if(mud->mqtt_state.recv_buffer_skip > in_buffer_length) {
NODE_DBG("MQTT[skipping]: skip=%u. Skipping full RX buffer (%u).\n",
mud->mqtt_state.recv_buffer_skip,
in_buffer_length
);
mud->mqtt_state.recv_buffer_skip -= in_buffer_length;
goto RX_PACKET_FINISHED;
}
NODE_DBG("MQTT[skipping]: skip=%u. Skipping partial RX buffer, continuing at %u\n",
mud->mqtt_state.recv_buffer_skip,
in_buffer_length
);
in_buffer += mud->mqtt_state.recv_buffer_skip;
in_buffer_length -= mud->mqtt_state.recv_buffer_skip;
mud->mqtt_state.recv_buffer_skip = 0;
mud->mqtt_state.recv_buffer_state = MQTT_RECV_NORMAL;
break;
}
READPACKET:
if(in_buffer_length <= 0)
goto RX_PACKET_FINISHED;
// MQTT publish message can in theory be 256Mb, while we do not support it we need to be
// able to do math on it.
int32_t message_length;
// temp buffer for control messages
uint8_t temp_buffer[MQTT_BUF_SIZE];
mqtt_msg_init(&mud->mqtt_state.mqtt_connection, temp_buffer, MQTT_BUF_SIZE);
mqtt_message_t *temp_msg = NULL;
......@@ -355,19 +482,107 @@ READPACKET:
break;
case MQTT_DATA:
mud->mqtt_state.message_length_read = length;
mud->mqtt_state.message_length = mqtt_get_total_length(in_buffer, mud->mqtt_state.message_length_read);
message_length = mqtt_get_total_length(in_buffer, in_buffer_length);
msg_type = mqtt_get_type(in_buffer);
msg_qos = mqtt_get_qos(in_buffer);
msg_id = mqtt_get_id(in_buffer, mud->mqtt_state.message_length);
msg_id = mqtt_get_id(in_buffer, in_buffer_length);
NODE_DBG("MQTT_DATA: msg length: %u, buffer length: %u\r\n",
message_length,
in_buffer_length);
if (message_length > mud->connect_info.max_message_length) {
// The pending message length is larger than we was configured to allow
if(msg_qos > 0 && msg_id == 0) {
NODE_DBG("MQTT: msg too long, but not enough data to get msg_id: total=%u, deliver=%u\r\n", message_length, in_buffer_length);
// qos requested, but too short buffer to get a packet ID.
// Trigger the "short buffer" mode
message_length = -1;
// Drop through to partial message handling below.
} else {
NODE_DBG("MQTT: msg too long: total=%u, deliver=%u\r\n", message_length, in_buffer_length);
if (msg_type == MQTT_MSG_TYPE_PUBLISH) {
// In practice we should never get any other types..
deliver_publish(mud, in_buffer, in_buffer_length, 1);
// If qos specified, we should ACK it.
// In theory it might be wrong to ack it before we received all TCP packets, but this avoids
// buffering and special code to handle this corner-case. Server will most likely have
// written all to OS socket anyway, and not be aware that we "should" not have received it all yet.
if(msg_qos == 1){
temp_msg = mqtt_msg_puback(&mud->mqtt_state.mqtt_connection, msg_id);
msg_enqueue(&(mud->mqtt_state.pending_msg_q), temp_msg,
msg_id, MQTT_MSG_TYPE_PUBACK, (int)mqtt_get_qos(temp_msg->data) );
}
else if(msg_qos == 2){
temp_msg = mqtt_msg_pubrec(&mud->mqtt_state.mqtt_connection, msg_id);
msg_enqueue(&(mud->mqtt_state.pending_msg_q), temp_msg,
msg_id, MQTT_MSG_TYPE_PUBREC, (int)mqtt_get_qos(temp_msg->data) );
}
if(msg_qos == 1 || msg_qos == 2){
NODE_DBG("MQTT: Queue response QoS: %d\r\n", msg_qos);
}
}
msg_queue_t *pending_msg = msg_peek(&(mud->mqtt_state.pending_msg_q));
if (message_length > in_buffer_length) {
// Ignore bytes in subsequent packet(s) too.
NODE_DBG("MQTT: skipping into next rx\n");
mud->mqtt_state.recv_buffer_state = MQTT_RECV_SKIPPING;
mud->mqtt_state.recv_buffer_skip = (uint32_t) message_length - in_buffer_length;
break;
} else {
NODE_DBG("MQTT: Skipping message\n");
mud->mqtt_state.recv_buffer_state = MQTT_RECV_NORMAL;
goto RX_MESSAGE_PROCESSED;
}
}
}
if (message_length == -1 || message_length > in_buffer_length) {
// Partial message in buffer, need to store on heap until next RX. Allocate size for full message directly,
// instead of potential reallocs, to avoid fragmentation.
// If message_length is indicated as -1, we do not have enough data to determine the length properly.
// Just put what we have on heap, and place in state BUFFERING_SHORT.
NODE_DBG("MQTT: Partial message received (%u of %d). Buffering\r\n",
in_buffer_length,
message_length);
// although message_length is 32bit, it should never go above 16bit since
// max_message_length is 16bit.
uint16_t alloc_size = message_length > 0 ? (uint16_t)message_length : in_buffer_length;
mud->mqtt_state.recv_buffer = c_zalloc(alloc_size);
if (mud->mqtt_state.recv_buffer == NULL) {
NODE_DBG("MQTT: Failed to allocate %u bytes, disconnecting...\n", alloc_size);
#ifdef CLIENT_SSL_ENABLE
if (mud->secure) {
espconn_secure_disconnect(pesp_conn);
} else
#endif
{
espconn_disconnect(pesp_conn);
}
return;
}
NODE_DBG("MQTT_DATA: type: %d, qos: %d, msg_id: %d, pending_id: %d\r\n",
memcpy(mud->mqtt_state.recv_buffer, in_buffer, in_buffer_length);
mud->mqtt_state.recv_buffer_wp = mud->mqtt_state.recv_buffer + in_buffer_length;
mud->mqtt_state.recv_buffer_state = message_length > 0 ? MQTT_RECV_BUFFERING : MQTT_RECV_BUFFERING_SHORT;
mud->mqtt_state.recv_buffer_size = alloc_size;
NODE_DBG("MQTT: Wait for next recv\n");
break;
}
msg_queue_t *pending_msg = msg_peek(&(mud->mqtt_state.pending_msg_q));
NODE_DBG("MQTT_DATA: type: %d, qos: %d, msg_id: %d, pending_id: %d, msg length: %u, buffer length: %u\r\n",
msg_type,
msg_qos,
msg_id,
(pending_msg)?pending_msg->msg_id:0);
(pending_msg)?pending_msg->msg_id:0,
message_length,
in_buffer_length);
switch(msg_type)
{
case MQTT_MSG_TYPE_SUBACK:
......@@ -411,7 +626,7 @@ READPACKET:
if(msg_qos == 1 || msg_qos == 2){
NODE_DBG("MQTT: Queue response QoS: %d\r\n", msg_qos);
}
deliver_publish(mud, in_buffer, mud->mqtt_state.message_length);
deliver_publish(mud, in_buffer, (uint16_t)message_length, 0);
break;
case MQTT_MSG_TYPE_PUBACK:
if(pending_msg && pending_msg->msg_type == MQTT_MSG_TYPE_PUBLISH && pending_msg->msg_id == msg_id){
......@@ -472,28 +687,40 @@ READPACKET:
NODE_DBG("MQTT: PINGRESP received\r\n");
break;
}
// NOTE: this is done down here and not in the switch case above
// because the PSOCK_READBUF_LEN() won't work inside a switch
// statement due to the way protothreads resume.
if(msg_type == MQTT_MSG_TYPE_PUBLISH)
{
length = mud->mqtt_state.message_length_read;
RX_MESSAGE_PROCESSED:
if(continuation_buffer != NULL) {
NODE_DBG("MQTT[buffering]: buffered message finished. Continuing with rest of rx buffer (%u)\n",
len);
c_free(mud->mqtt_state.recv_buffer);
mud->mqtt_state.recv_buffer = NULL;
if(mud->mqtt_state.message_length < mud->mqtt_state.message_length_read)
{
length -= mud->mqtt_state.message_length;
in_buffer += mud->mqtt_state.message_length;
in_buffer = continuation_buffer;
in_buffer_length = len;
continuation_buffer = NULL;
}else{
// Message have been fully processed (or ignored). Move pointer ahead
// and continue with next message, if any.
in_buffer_length -= message_length;
in_buffer += message_length;
}
if(in_buffer_length > 0)
{
NODE_DBG("Get another published message\r\n");
goto READPACKET;
}
}
break;
}
RX_PACKET_FINISHED:
if(temp_pdata != NULL) {
c_free(temp_pdata);
}
mqtt_send_if_possible(pesp_conn);
NODE_DBG("leave mqtt_socket_received.\n");
NODE_DBG("leave mqtt_socket_received\n");
return;
}
......@@ -580,7 +807,7 @@ static void mqtt_socket_connected(void *arg)
mud->keep_alive_tick = 0;
mud->connState = MQTT_CONNECT_SENDING;
NODE_DBG("leave mqtt_socket_connected.\n");
NODE_DBG("leave mqtt_socket_connectet, heap = %u.\n", system_get_free_heap_size());
return;
}
......@@ -686,7 +913,7 @@ void mqtt_socket_timer(void *arg)
NODE_DBG("leave mqtt_socket_timer.\n");
}
// Lua: mqtt.Client(clientid, keepalive, user, pass, clean_session)
// Lua: mqtt.Client(clientid, keepalive, user, pass, clean_session, max_message_length)
static int mqtt_socket_client( lua_State* L )
{
NODE_DBG("enter mqtt_socket_client.\n");
......@@ -703,6 +930,7 @@ static int mqtt_socket_client( lua_State* L )
int keepalive = 0;
int stack = 1;
int clean_session = 1;
int max_message_length = 0;
int top = lua_gettop(L);
// create a object
......@@ -715,6 +943,7 @@ static int mqtt_socket_client( lua_State* L )
mud->cb_disconnect_ref = LUA_NOREF;
mud->cb_message_ref = LUA_NOREF;
mud->cb_overflow_ref = LUA_NOREF;
mud->cb_suback_ref = LUA_NOREF;
mud->cb_unsuback_ref = LUA_NOREF;
mud->cb_puback_ref = LUA_NOREF;
......@@ -767,6 +996,16 @@ static int mqtt_socket_client( lua_State* L )
clean_session = 1;
}
if(lua_isnumber( L, stack ))
{
max_message_length = luaL_checkinteger( L, stack);
stack++;
}
if(max_message_length == 0) {
max_message_length = DEFAULT_MAX_MESSAGE_LENGTH;
}
// TODO: check the zalloc result.
mud->connect_info.client_id = (uint8_t *)c_zalloc(idl+1);
mud->connect_info.username = (uint8_t *)c_zalloc(unl + 1);
......@@ -800,11 +1039,15 @@ static int mqtt_socket_client( lua_State* L )
mud->connect_info.will_qos = 0;
mud->connect_info.will_retain = 0;
mud->connect_info.keepalive = keepalive;
mud->connect_info.max_message_length = max_message_length;
mud->mqtt_state.pending_msg_q = NULL;
mud->mqtt_state.auto_reconnect = RECONNECT_OFF;
mud->mqtt_state.port = 1883;
mud->mqtt_state.connect_info = &mud->connect_info;
mud->mqtt_state.recv_buffer = NULL;
mud->mqtt_state.recv_buffer_size = 0;
mud->mqtt_state.recv_buffer_state = MQTT_RECV_NORMAL;
NODE_DBG("leave mqtt_socket_client.\n");
return 1;
......@@ -852,6 +1095,13 @@ static int mqtt_delete( lua_State* L )
}
// ----
//--------- alloc-ed in mqtt_socket_received()
if(mud->mqtt_state.recv_buffer) {
c_free(mud->mqtt_state.recv_buffer);
mud->mqtt_state.recv_buffer = NULL;
}
// ----
//--------- alloc-ed in mqtt_socket_client()
if(mud->connect_info.client_id){
c_free(mud->connect_info.client_id);
......@@ -876,6 +1126,8 @@ static int mqtt_delete( lua_State* L )
mud->cb_disconnect_ref = LUA_NOREF;
luaL_unref(L, LUA_REGISTRYINDEX, mud->cb_message_ref);
mud->cb_message_ref = LUA_NOREF;
luaL_unref(L, LUA_REGISTRYINDEX, mud->cb_overflow_ref);
mud->cb_overflow_ref = LUA_NOREF;
luaL_unref(L, LUA_REGISTRYINDEX, mud->cb_suback_ref);
mud->cb_suback_ref = LUA_NOREF;
luaL_unref(L, LUA_REGISTRYINDEX, mud->cb_unsuback_ref);
......@@ -918,7 +1170,7 @@ static sint8 socket_connect(struct espconn *pesp_conn)
os_timer_arm(&mud->mqttTimer, 1000, 1);
NODE_DBG("leave socket_connect, heap = %u.\n", system_get_free_heap_size());
NODE_DBG("leave socket_connect\n");
return espconn_status;
}
......@@ -1225,6 +1477,9 @@ static int mqtt_socket_on( lua_State* L )
}else if( sl == 7 && c_strcmp(method, "message") == 0){
luaL_unref(L, LUA_REGISTRYINDEX, mud->cb_message_ref);
mud->cb_message_ref = luaL_ref(L, LUA_REGISTRYINDEX);
}else if( sl == 8 && c_strcmp(method, "overflow") == 0){
luaL_unref(L, LUA_REGISTRYINDEX, mud->cb_overflow_ref);
mud->cb_overflow_ref = luaL_ref(L, LUA_REGISTRYINDEX);
}else{
lua_pop(L, 1);
return luaL_error( L, "method not supported" );
......
......@@ -378,22 +378,6 @@ static int tmr_create( lua_State *L ) {
}
#if defined(ENABLE_TIMER_SUSPEND) && defined(SWTMR_DEBUG)
static void tmr_printRegistry(lua_State* L){
swtmr_print_registry();
}
static void tmr_printSuspended(lua_State* L){
swtmr_print_suspended();
}
static void tmr_printTimerlist(lua_State* L){
swtmr_print_timer_list();
}
#endif
// Module function map
static const LUA_REG_TYPE tmr_dyn_map[] = {
......
This diff is collapsed.
......@@ -570,9 +570,9 @@ static int packet_map_lookup(lua_State *L) {
}
// Now search the packet function map
const TValue *res = luaR_findentry((void *) packet_function_map, field, 0, NULL);
if (res) {
luaA_pushobject(L, res);
lua_pushrotable(L, (void *)packet_function_map);
lua_getfield(L, -1, field);
if (!lua_isnil(L, -1)) {
return 1;
}
}
......
......@@ -126,12 +126,16 @@ void mqtt_msg_init(mqtt_connection_t* connection, uint8_t* buffer, uint16_t buff
connection->buffer_length = buffer_length;
}
int mqtt_get_total_length(uint8_t* buffer, uint16_t length)
// Returns total length of message, or -1 if not enough bytes are available
int32_t mqtt_get_total_length(uint8_t* buffer, uint16_t buffer_length)
{
int i;
int totlen = 0;
for(i = 1; i < length; ++i)
if(buffer_length == 1)
return -1;
for(i = 1; i < buffer_length; ++i)
{
totlen += (buffer[i] & 0x7f) << (7 * (i - 1));
if((buffer[i] & 0x80) == 0)
......@@ -139,19 +143,23 @@ int mqtt_get_total_length(uint8_t* buffer, uint16_t length)
++i;
break;
}
if(i == buffer_length)
return -1;
}
totlen += i;
return totlen;
}
const char* mqtt_get_publish_topic(uint8_t* buffer, uint16_t* length)
const char* mqtt_get_publish_topic(uint8_t* buffer, uint16_t* buffer_length)
{
int i;
int totlen = 0;
int topiclen;
for(i = 1; i < *length; ++i)
for(i = 1; i < *buffer_length; ++i)
{
totlen += (buffer[i] & 0x7f) << (7 * (i -1));
if((buffer[i] & 0x80) == 0)
......@@ -162,25 +170,25 @@ const char* mqtt_get_publish_topic(uint8_t* buffer, uint16_t* length)
}
totlen += i;
if(i + 2 > *length)
if(i + 2 > *buffer_length)
return NULL;
topiclen = buffer[i++] << 8;
topiclen |= buffer[i++];
if(i + topiclen > *length)
if(i + topiclen > *buffer_length)
return NULL;
*length = topiclen;
*buffer_length = topiclen;
return (const char*)(buffer + i);
}
const char* mqtt_get_publish_data(uint8_t* buffer, uint16_t* length)
const char* mqtt_get_publish_data(uint8_t* buffer, uint16_t* buffer_length)
{
int i;
int totlen = 0;
int topiclen;
for(i = 1; i < *length; ++i)
for(i = 1; i < *buffer_length; ++i)
{
totlen += (buffer[i] & 0x7f) << (7 * (i - 1));
if((buffer[i] & 0x80) == 0)
......@@ -191,20 +199,20 @@ const char* mqtt_get_publish_data(uint8_t* buffer, uint16_t* length)
}
totlen += i;
if(i + 2 > *length)
if(i + 2 > *buffer_length)
return NULL;
topiclen = buffer[i++] << 8;
topiclen |= buffer[i++];
if(i + topiclen > *length){
*length = 0;
if(i + topiclen > *buffer_length){
*buffer_length = 0;
return NULL;
}
i += topiclen;
if(mqtt_get_qos(buffer) > 0)
{
if(i + 2 > *length)
if(i + 2 > *buffer_length)
return NULL;
i += 2;
}
......@@ -212,16 +220,16 @@ const char* mqtt_get_publish_data(uint8_t* buffer, uint16_t* length)
if(totlen < i)
return NULL;
if(totlen <= *length)
*length = totlen - i;
if(totlen <= *buffer_length)
*buffer_length = totlen - i;
else
*length = *length - i;
*buffer_length = *buffer_length - i;
return (const char*)(buffer + i);
}
uint16_t mqtt_get_id(uint8_t* buffer, uint16_t length)
uint16_t mqtt_get_id(uint8_t* buffer, uint16_t buffer_length)
{
if(length < 1)
if(buffer_length < 1)
return 0;
switch(mqtt_get_type(buffer))
......@@ -234,7 +242,7 @@ uint16_t mqtt_get_id(uint8_t* buffer, uint16_t length)
if(mqtt_get_qos(buffer) <= 0)
return 0;
for(i = 1; i < length; ++i)
for(i = 1; i < buffer_length; ++i)
{
if((buffer[i] & 0x80) == 0)
{
......@@ -243,16 +251,16 @@ uint16_t mqtt_get_id(uint8_t* buffer, uint16_t length)
}
}
if(i + 2 > length)
if(i + 2 > buffer_length)
return 0;
topiclen = buffer[i++] << 8;
topiclen |= buffer[i++];
if(i + topiclen > length)
if(i + topiclen > buffer_length)
return 0;
i += topiclen;
if(i + 2 > length)
if(i + 2 > buffer_length)
return 0;
return (buffer[i] << 8) | buffer[i + 1];
......@@ -267,7 +275,7 @@ uint16_t mqtt_get_id(uint8_t* buffer, uint16_t length)
{
// This requires the remaining length to be encoded in 1 byte,
// which it should be.
if(length >= 4 && (buffer[1] & 0x80) == 0)
if(buffer_length >= 4 && (buffer[1] & 0x80) == 0)
return (buffer[2] << 8) | buffer[3];
else
return 0;
......
......@@ -108,21 +108,22 @@ typedef struct mqtt_connect_info
int will_qos;
int will_retain;
int clean_session;
uint16_t max_message_length;
} mqtt_connect_info_t;
static inline int mqtt_get_type(uint8_t* buffer) { return (buffer[0] & 0xf0) >> 4; }
static inline int mqtt_get_dup(uint8_t* buffer) { return (buffer[0] & 0x08) >> 3; }
static inline int mqtt_get_qos(uint8_t* buffer) { return (buffer[0] & 0x06) >> 1; }
static inline int mqtt_get_retain(uint8_t* buffer) { return (buffer[0] & 0x01); }
static inline int mqtt_get_connect_ret_code(uint8_t* buffer) { return (buffer[3]); }
static inline uint8_t mqtt_get_type(uint8_t* buffer) { return (buffer[0] & 0xf0) >> 4; }
static inline uint8_t mqtt_get_dup(uint8_t* buffer) { return (buffer[0] & 0x08) >> 3; }
static inline uint8_t mqtt_get_qos(uint8_t* buffer) { return (buffer[0] & 0x06) >> 1; }
static inline uint8_t mqtt_get_retain(uint8_t* buffer) { return (buffer[0] & 0x01); }
static inline uint8_t mqtt_get_connect_ret_code(uint8_t* buffer) { return (buffer[3]); }
void mqtt_msg_init(mqtt_connection_t* connection, uint8_t* buffer, uint16_t buffer_length);
int mqtt_get_total_length(uint8_t* buffer, uint16_t length);
const char* mqtt_get_publish_topic(uint8_t* buffer, uint16_t* length);
const char* mqtt_get_publish_data(uint8_t* buffer, uint16_t* length);
uint16_t mqtt_get_id(uint8_t* buffer, uint16_t length);
int32_t mqtt_get_total_length(uint8_t* buffer, uint16_t buffer_length);
const char* mqtt_get_publish_topic(uint8_t* buffer, uint16_t* buffer_length);
const char* mqtt_get_publish_data(uint8_t* buffer, uint16_t* buffer_length);
uint16_t mqtt_get_id(uint8_t* buffer, uint16_t buffer_length);
mqtt_message_t* mqtt_msg_connect(mqtt_connection_t* connection, mqtt_connect_info_t* info);
mqtt_message_t* mqtt_msg_publish(mqtt_connection_t* connection, const char* topic, const char* data, int data_length, int qos, int retain, uint16_t* message_id);
......
......@@ -44,6 +44,7 @@ INCLUDES += -I ../spiffs
INCLUDES += -I ../libc
INCLUDES += -I ../lua
INCLUDES += -I ../u8g2lib/u8g2/src/clib
INCLUDES += -I ../ucglib/ucg/src/clib
PDIR := ../$(PDIR)
sinclude $(PDIR)Makefile
......@@ -13,6 +13,42 @@
#define U8X8_USE_PINS
#include "u8x8_nodemcu_hal.h"
// static variables containing info about the i2c link
// TODO: move to user space in u8x8_t once available
typedef struct {
uint8_t id;
} hal_i2c_t;
// static variables containing info about the spi link
// TODO: move to user space in u8x8_t once available
typedef struct {
uint8_t host;
//spi_device_handle_t device;
uint8_t last_dc;
struct {
uint8_t *data;
size_t size, used;
} buffer;
} hal_spi_t;
static void flush_buffer_spi( hal_spi_t *hal )
{
if (hal->buffer.data && hal->buffer.used > 0) {
platform_spi_blkwrite( hal->host, hal->buffer.used, hal->buffer.data );
hal->buffer.used = 0;
}
}
static void force_flush_buffer(u8x8_t *u8x8)
{
// spi hal has a buffer that can be flushed
if (u8x8->byte_cb == u8x8_byte_nodemcu_spi) {
hal_spi_t *hal = ((u8g2_nodemcu_t *)u8x8)->hal;
flush_buffer_spi( hal );
}
}
uint8_t u8x8_gpio_and_delay_nodemcu(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
{
......@@ -35,24 +71,30 @@ uint8_t u8x8_gpio_and_delay_nodemcu(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int,
break;
case U8X8_MSG_DELAY_NANO: // delay arg_int * 1 nano second
force_flush_buffer(u8x8);
os_delay_us( 1 );
break;
case U8X8_MSG_DELAY_100NANO: // delay arg_int * 100 nano seconds
force_flush_buffer(u8x8);
temp = arg_int * 100;
temp /= 1000;
os_delay_us( temp > 0 ? temp : 1 );
break;
case U8X8_MSG_DELAY_10MICRO: // delay arg_int * 10 micro seconds
force_flush_buffer(u8x8);
os_delay_us( arg_int * 10 );
break;
case U8X8_MSG_DELAY_MILLI: // delay arg_int * 1 milli second
force_flush_buffer(u8x8);
os_delay_us( arg_int * 1000 );
system_soft_wdt_feed();
break;
case U8X8_MSG_DELAY_I2C: // arg_int is the I2C speed in 100KHz, e.g. 4 = 400 KHz
force_flush_buffer(u8x8);
temp = 5000 / arg_int; // arg_int=1: delay by 5us, arg_int = 4: delay by 1.25us
temp /= 1000;
os_delay_us( temp > 0 ? temp : 1 );
......@@ -119,12 +161,6 @@ uint8_t u8x8_gpio_and_delay_nodemcu(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int,
}
// static variables containing info about the i2c link
// TODO: move to user space in u8x8_t once available
typedef struct {
uint8_t id;
} hal_i2c_t;
uint8_t u8x8_byte_nodemcu_i2c(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
{
uint8_t *data;
......@@ -132,11 +168,11 @@ uint8_t u8x8_byte_nodemcu_i2c(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *
switch(msg) {
case U8X8_MSG_BYTE_SEND:
if (hal->id == 0) {
if (hal->id < NUM_I2C) {
data = (uint8_t *)arg_ptr;
while( arg_int > 0 ) {
platform_i2c_send_byte( 0, *data );
platform_i2c_send_byte( hal->id, *data );
data++;
arg_int--;
}
......@@ -163,9 +199,9 @@ uint8_t u8x8_byte_nodemcu_i2c(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *
break;
case U8X8_MSG_BYTE_START_TRANSFER:
if (hal->id == 0) {
platform_i2c_send_start( 0 );
platform_i2c_send_address( 0, u8x8_GetI2CAddress(u8x8), PLATFORM_I2C_DIRECTION_TRANSMITTER );
if (hal->id < NUM_I2C) {
platform_i2c_send_start( hal->id );
platform_i2c_send_address( hal->id, u8x8_GetI2CAddress(u8x8), PLATFORM_I2C_DIRECTION_TRANSMITTER );
} else {
// invalid id
......@@ -174,8 +210,8 @@ uint8_t u8x8_byte_nodemcu_i2c(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *
break;
case U8X8_MSG_BYTE_END_TRANSFER:
if (hal->id == 0) {
platform_i2c_send_stop( 0 );
if (hal->id < NUM_I2C) {
platform_i2c_send_stop( hal->id );
} else {
// invalid id
......@@ -191,27 +227,6 @@ uint8_t u8x8_byte_nodemcu_i2c(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *
}
// static variables containing info about the spi link
// TODO: move to user space in u8x8_t once available
typedef struct {
uint8_t host;
//spi_device_handle_t device;
uint8_t last_dc;
struct {
uint8_t *data;
size_t size, used;
} buffer;
} hal_spi_t;
static void flush_buffer_spi( hal_spi_t *hal )
{
if (hal->buffer.used > 0) {
platform_spi_blkwrite( hal->host, hal->buffer.used, hal->buffer.data );
hal->buffer.used = 0;
}
}
uint8_t u8x8_byte_nodemcu_spi(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
{
hal_spi_t *hal = ((u8g2_nodemcu_t *)u8x8)->hal;
......@@ -228,6 +243,7 @@ uint8_t u8x8_byte_nodemcu_spi(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *
return 0;
hal->host = host;
((u8g2_nodemcu_t *)u8x8)->hal = hal;
hal->buffer.data = NULL;
hal->last_dc = 0;
}
......@@ -279,6 +295,7 @@ uint8_t u8x8_byte_nodemcu_spi(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *
u8x8_gpio_SetCS( u8x8, u8x8->display_info->chip_disable_level );
c_free( hal->buffer.data );
hal->buffer.data = NULL;
break;
default:
......
// Do not use the code from ucg submodule and skip the complete source here
// if the ucg module is not selected.
// Reason: The whole ucg submodule code tree might not even exist in this case.
#include "user_modules.h"
#ifdef LUA_USE_MODULES_UCG
#include <string.h>
#include "c_stdlib.h"
#include "platform.h"
#define USE_PIN_LIST
#include "ucg_nodemcu_hal.h"
#define delayMicroseconds os_delay_us
static spi_data_type cache;
static uint8_t cached;
#define CACHED_TRANSFER(dat, num) cache = cached = 0; \
while( arg > 0 ) { \
if (cached == 4) { \
platform_spi_transaction( 1, 0, 0, 32, cache, 0, 0, 0 ); \
cache = cached = 0; \
} \
cache = (cache << num*8) | dat; \
cached += num; \
arg--; \
} \
if (cached > 0) { \
platform_spi_transaction( 1, 0, 0, cached * 8, cache, 0, 0, 0 ); \
}
int16_t ucg_com_nodemcu_hw_spi(ucg_t *ucg, int16_t msg, uint16_t arg, uint8_t *data)
{
switch(msg)
{
case UCG_COM_MSG_POWER_UP:
/* "data" is a pointer to ucg_com_info_t structure with the following information: */
/* ((ucg_com_info_t *)data)->serial_clk_speed value in nanoseconds */
/* ((ucg_com_info_t *)data)->parallel_clk_speed value in nanoseconds */
/* setup pins */
// we assume that the SPI interface was already initialized
// just care for the /CS and D/C pins
//platform_gpio_write( ucg->pin_list[0], value );
if ( ucg->pin_list[UCG_PIN_RST] != UCG_PIN_VAL_NONE )
platform_gpio_mode( ucg->pin_list[UCG_PIN_RST], PLATFORM_GPIO_OUTPUT, PLATFORM_GPIO_FLOAT );
platform_gpio_mode( ucg->pin_list[UCG_PIN_CD], PLATFORM_GPIO_OUTPUT, PLATFORM_GPIO_FLOAT );
if ( ucg->pin_list[UCG_PIN_CS] != UCG_PIN_VAL_NONE )
platform_gpio_mode( ucg->pin_list[UCG_PIN_CS], PLATFORM_GPIO_OUTPUT, PLATFORM_GPIO_FLOAT );
break;
case UCG_COM_MSG_POWER_DOWN:
break;
case UCG_COM_MSG_DELAY:
delayMicroseconds(arg);
break;
case UCG_COM_MSG_CHANGE_RESET_LINE:
if ( ucg->pin_list[UCG_PIN_RST] != UCG_PIN_VAL_NONE )
platform_gpio_write( ucg->pin_list[UCG_PIN_RST], arg );
break;
case UCG_COM_MSG_CHANGE_CS_LINE:
if ( ucg->pin_list[UCG_PIN_CS] != UCG_PIN_VAL_NONE )
platform_gpio_write( ucg->pin_list[UCG_PIN_CS], arg );
break;
case UCG_COM_MSG_CHANGE_CD_LINE:
platform_gpio_write( ucg->pin_list[UCG_PIN_CD], arg );
break;
case UCG_COM_MSG_SEND_BYTE:
platform_spi_send( 1, 8, arg );
break;
case UCG_COM_MSG_REPEAT_1_BYTE:
CACHED_TRANSFER(data[0], 1);
break;
case UCG_COM_MSG_REPEAT_2_BYTES:
CACHED_TRANSFER((data[0] << 8) | data[1], 2);
break;
case UCG_COM_MSG_REPEAT_3_BYTES:
while( arg > 0 ) {
platform_spi_transaction( 1, 0, 0, 24, (data[0] << 16) | (data[1] << 8) | data[2], 0, 0, 0 );
arg--;
}
break;
case UCG_COM_MSG_SEND_STR:
CACHED_TRANSFER(*data++, 1);
break;
case UCG_COM_MSG_SEND_CD_DATA_SEQUENCE:
while(arg > 0)
{
if ( *data != 0 )
{
/* set the data line directly, ignore the setting from UCG_CFG_CD */
if ( *data == 1 )
{
platform_gpio_write( ucg->pin_list[UCG_PIN_CD], 0 );
}
else
{
platform_gpio_write( ucg->pin_list[UCG_PIN_CD], 1 );
}
}
data++;
platform_spi_send( 1, 8, *data );
data++;
arg--;
}
break;
}
return 1;
}
#endif /* LUA_USE_MODULES_UCG */
#ifndef _UCG_NODEMCU_HAL_H
#define _UCG_NODEMCU_HAL_H
#include "ucg.h"
// extend standard ucg_t struct with info that's needed in the communication callbacks
typedef struct {
ucg_t ucg;
void *hal;
} ucg_nodemcu_t;
int16_t ucg_com_nodemcu_hw_spi(ucg_t *ucg, int16_t msg, uint16_t arg, uint8_t *data);
#endif /* _UCG_NODEMCU_HAL_H */
Subproject commit 7f2fc42af3d01fdfe2cc19320bdcfe693dd2b20d
Subproject commit d4da8254220adf39db44faa52a0842967095d230
......@@ -24,7 +24,7 @@ STD_CFLAGS=-std=gnu11 -Wimplicit
# makefile at its root level - these are then overridden
# for a subtree within the makefile rooted therein
#
#DEFINES +=
DEFINES += -DUSE_PIN_LIST
#############################################################
# Recursion Magic - Don't touch this!!
......@@ -38,7 +38,10 @@ STD_CFLAGS=-std=gnu11 -Wimplicit
# Required for each makefile to inherit from the parent
#
CSRCS := $(wildcard ucg/src/clib/*.c *.c)
INCLUDES := $(INCLUDES) -I $(PDIR)include
INCLUDES += -I ucg/src/clib
INCLUDES += -I ./
INCLUDES += -I ../libc
PDIR := ../$(PDIR)
......
Subproject commit e21641a6c1ddb0e71f7b9e01501fa739786c68b1
This diff is collapsed.
/*
ucg_bitmap.c
Universal uC Color Graphics Library
Copyright (c) 2013, olikraus@gmail.com
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list
of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or other
materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "ucg.h"
#ifdef UCG_MSG_DRAW_L90TC
void ucg_DrawTransparentBitmapLine(ucg_t *ucg, ucg_int_t x, ucg_int_t y, ucg_int_t dir, ucg_int_t len, const unsigned char *bitmap)
{
ucg->arg.pixel.rgb.color[0] = ucg->arg.rgb[0].color[0];
ucg->arg.pixel.rgb.color[1] = ucg->arg.rgb[0].color[1];
ucg->arg.pixel.rgb.color[2] = ucg->arg.rgb[0].color[2];
ucg->arg.pixel.pos.x = x;
ucg->arg.pixel.pos.y = y;
ucg->arg.dir = dir;
ucg->arg.len = len;
ucg->arg.bitmap = bitmap;
ucg->arg.pixel_skip = 0;
ucg_DrawL90TCWithArg(ucg);
}
#endif /* UCG_MSG_DRAW_L90TC */
#ifdef UCG_MSG_DRAW_L90BF
void ucg_DrawBitmapLine(ucg_t *ucg, ucg_int_t x, ucg_int_t y, ucg_int_t dir, ucg_int_t len, const unsigned char *bitmap)
{
/*
ucg->arg.pixel.rgb.color[0] = ucg->arg.rgb[0].color[0];
ucg->arg.pixel.rgb.color[1] = ucg->arg.rgb[0].color[1];
ucg->arg.pixel.rgb.color[2] = ucg->arg.rgb[0].color[2];
*/
ucg->arg.pixel.pos.x = x;
ucg->arg.pixel.pos.y = y;
ucg->arg.dir = dir;
ucg->arg.len = len;
ucg->arg.bitmap = bitmap;
ucg->arg.pixel_skip = 0;
//ucg->arg.scale = 0;
ucg_DrawL90BFWithArg(ucg);
}
#endif /* UCG_MSG_DRAW_L90BF */
#ifdef ON_HOLD
void ucg_DrawRLBitmap(ucg_t *ucg, ucg_int_t x, ucg_int_t y, ucg_int_t dir, const unsigned char *rl_bitmap)
{
ucg->arg.pixel.rgb.color[0] = ucg->arg.rgb[0].color[0];
ucg->arg.pixel.rgb.color[1] = ucg->arg.rgb[0].color[1];
ucg->arg.pixel.rgb.color[2] = ucg->arg.rgb[0].color[2];
ucg->arg.pixel.pos.x = x;
ucg->arg.pixel.pos.y = y;
ucg->arg.dir = dir;
ucg->arg.len = 0;
ucg->arg.bitmap = rl_bitmap;
ucg_DrawL90RLWithArg(ucg);
}
#endif
/*
ucg_box.c
Universal uC Color Graphics Library
Copyright (c) 2013, olikraus@gmail.com
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list
of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or other
materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "ucg.h"
void ucg_DrawBox(ucg_t *ucg, ucg_int_t x, ucg_int_t y, ucg_int_t w, ucg_int_t h)
{
while( h > 0 )
{
ucg_DrawHLine(ucg, x, y, w);
h--;
y++;
}
}
/*
- clear the screen with black color
- reset clip range to max
- set draw color to white
*/
void ucg_ClearScreen(ucg_t *ucg)
{
ucg_SetColor(ucg, 0, 0, 0, 0);
ucg_SetMaxClipRange(ucg);
ucg_DrawBox(ucg, 0, 0, ucg_GetWidth(ucg), ucg_GetHeight(ucg));
ucg_SetColor(ucg, 0, 255, 255, 255);
}
void ucg_DrawRBox(ucg_t *ucg, ucg_int_t x, ucg_int_t y, ucg_int_t w, ucg_int_t h, ucg_int_t r)
{
ucg_int_t xl, yu;
ucg_int_t yl, xr;
xl = x;
xl += r;
yu = y;
yu += r;
xr = x;
xr += w;
xr -= r;
xr -= 1;
yl = y;
yl += h;
yl -= r;
yl -= 1;
ucg_DrawDisc(ucg, xl, yu, r, UCG_DRAW_UPPER_LEFT);
ucg_DrawDisc(ucg, xr, yu, r, UCG_DRAW_UPPER_RIGHT);
ucg_DrawDisc(ucg, xl, yl, r, UCG_DRAW_LOWER_LEFT);
ucg_DrawDisc(ucg, xr, yl, r, UCG_DRAW_LOWER_RIGHT);
{
ucg_int_t ww, hh;
ww = w;
ww -= r;
ww -= r;
ww -= 2;
hh = h;
hh -= r;
hh -= r;
hh -= 2;
xl++;
yu++;
h--;
ucg_DrawBox(ucg, xl, y, ww, r+1);
ucg_DrawBox(ucg, xl, yl, ww, r+1);
ucg_DrawBox(ucg, x, yu, w, hh);
}
}
ucg_ccs_t ucg_ccs_box[6]; /* color component sliders used by GradientBox */
void ucg_DrawGradientBox(ucg_t *ucg, ucg_int_t x, ucg_int_t y, ucg_int_t w, ucg_int_t h)
{
uint8_t i;
/* Setup ccs for l90se. This will be updated by ucg_clip_l90se if required */
/* 8. Jan 2014: correct? */
//printf("%d %d %d\n", ucg->arg.rgb[3].color[0], ucg->arg.rgb[3].color[1], ucg->arg.rgb[3].color[2]);
for ( i = 0; i < 3; i++ )
{
ucg_ccs_init(ucg_ccs_box+i, ucg->arg.rgb[0].color[i], ucg->arg.rgb[2].color[i], h);
ucg_ccs_init(ucg_ccs_box+i+3, ucg->arg.rgb[1].color[i], ucg->arg.rgb[3].color[i], h);
}
while( h > 0 )
{
ucg->arg.rgb[0].color[0] = ucg_ccs_box[0].current;
ucg->arg.rgb[0].color[1] = ucg_ccs_box[1].current;
ucg->arg.rgb[0].color[2] = ucg_ccs_box[2].current;
ucg->arg.rgb[1].color[0] = ucg_ccs_box[3].current;
ucg->arg.rgb[1].color[1] = ucg_ccs_box[4].current;
ucg->arg.rgb[1].color[2] = ucg_ccs_box[5].current;
//printf("%d %d %d\n", ucg_ccs_box[0].current, ucg_ccs_box[1].current, ucg_ccs_box[2].current);
//printf("%d %d %d\n", ucg_ccs_box[3].current, ucg_ccs_box[4].current, ucg_ccs_box[5].current);
ucg->arg.pixel.pos.x = x;
ucg->arg.pixel.pos.y = y;
ucg->arg.len = w;
ucg->arg.dir = 0;
ucg_DrawL90SEWithArg(ucg);
for ( i = 0; i < 6; i++ )
ucg_ccs_step(ucg_ccs_box+i);
h--;
y++;
}
}
/* restrictions: w > 0 && h > 0 */
void ucg_DrawFrame(ucg_t *ucg, ucg_int_t x, ucg_int_t y, ucg_int_t w, ucg_int_t h)
{
ucg_int_t xtmp = x;
ucg_DrawHLine(ucg, x, y, w);
ucg_DrawVLine(ucg, x, y, h);
x+=w;
x--;
ucg_DrawVLine(ucg, x, y, h);
y+=h;
y--;
ucg_DrawHLine(ucg, xtmp, y, w);
}
void ucg_DrawRFrame(ucg_t *ucg, ucg_int_t x, ucg_int_t y, ucg_int_t w, ucg_int_t h, ucg_int_t r)
{
ucg_int_t xl, yu;
xl = x;
xl += r;
yu = y;
yu += r;
{
ucg_int_t yl, xr;
xr = x;
xr += w;
xr -= r;
xr -= 1;
yl = y;
yl += h;
yl -= r;
yl -= 1;
ucg_DrawCircle(ucg, xl, yu, r, UCG_DRAW_UPPER_LEFT);
ucg_DrawCircle(ucg, xr, yu, r, UCG_DRAW_UPPER_RIGHT);
ucg_DrawCircle(ucg, xl, yl, r, UCG_DRAW_LOWER_LEFT);
ucg_DrawCircle(ucg, xr, yl, r, UCG_DRAW_LOWER_RIGHT);
}
{
ucg_int_t ww, hh;
ww = w;
ww -= r;
ww -= r;
ww -= 2;
hh = h;
hh -= r;
hh -= r;
hh -= 2;
xl++;
yu++;
h--;
w--;
ucg_DrawHLine(ucg, xl, y, ww);
ucg_DrawHLine(ucg, xl, y+h, ww);
ucg_DrawVLine(ucg, x, yu, hh);
ucg_DrawVLine(ucg, x+w, yu, hh);
}
}
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