/*
* AWS Starter-kit Ultrasonic-sensor Application
*
* Summary:
*
* Device publishes the changed state of the distance obtained through ultrasonic
* sensor on Thing Shadow. Also it subscribes to the Thing Shadow delta and when state
* change of LED is requested from AWS IOT web console, it toggles the LED
* state.
*
* The serial console is set on UART-0.
*
* A serial terminal program like minicom can be used to see the program output.
*/
#include <wm_os.h>
#include <wmstdio.h>
#include <wmtime.h>
#include <wmsdk.h>
#include <board.h>
#include <mdev_gpio.h>
#include <mdev_pinmux.h>
#include <lowlevel_drivers.h>
#include <led_indicator.h>
#include <push_button.h>
#include <aws_iot_mqtt_interface.h>
#include <aws_iot_shadow_interface.h>
#include <aws_utils.h>
/* configuration parameters */
#include "sensor_drv.h"
#include <aws_iot_config.h>
#include "sensor_ultrasonic_drv.h"
#include "aws_starter_root_ca_cert.h"
#define ULTRASONIC_SEN_IO GPIO_0
#define ULTRASONIC_SEN_IO_OUT GPIO_1
#define ULTRASONIC_SEN_IO_GPIO GPIO0_GPIO0
#define ULTRASONIC_SEN_IO_GPIO_OUT GPIO1_GPIO1
/* define this to test sensor w/o cloud */
#undef ULTRASONIC_SENSOR_TEST
#ifdef ULTRASONIC_SENSOR_TEST
void check_ultrasonic_sensor(void);
#endif /* ULTRASONIC_SENSOR_TEST */
enum state {
AWS_CONNECTED = 1,
AWS_RECONNECTED,
AWS_DISCONNECTED
};
/*----------------------------------------------------------------------------*/
/*-----------------------Global declarations----------------------*/
/* These hold each pushbutton's count, updated in the callback ISR */
static volatile uint32_t pushbutton_a_count;
static volatile uint32_t pushbutton_a_count_prev = -1;
static volatile uint32_t pushbutton_b_count;
static volatile uint32_t pushbutton_b_count_prev = -1;
static volatile uint32_t led_1_state;
static volatile uint32_t led_1_state_prev = -1;
static output_gpio_cfg_t led_1;
static MQTTClient_t mqtt_client;
static enum state device_state;
/* Thread handle */
static os_thread_t aws_starter_thread;
/* Buffer to be used as stack */
static os_thread_stack_define(aws_starter_stack, 12 * 1024);
/* aws iot url */
static char url[128];
#define MICRO_AP_SSID "aws_starter"
#define MICRO_AP_PASSPHRASE "marvellwm"
#define AMAZON_ACTION_BUF_SIZE 100
#define VAR_LED_1_PROPERTY "led"
#define VAR_BUTTON_A_PROPERTY "pb"
#define VAR_BUTTON_B_PROPERTY "pb_lambda"
#define RESET_TO_FACTORY_TIMEOUT 5000
#define BUFSIZE 128
#define MAX_MAC_BYTES 6
int distance=0 , distance_prev=-1;
#define VAR_ULTRA_PROPERTY "ultra"
/*--------------------------------------------------------------------------*/
/* callback function invoked on reset to factory */
static void device_reset_to_factory_cb()
{
/* Clears device configuration settings from persistent memory
* and reboots the device.
*/
invoke_reset_to_factory();
}
/* board_button_2() is configured to perform reset to factory,
* when pressed for more than 5 seconds.
*/
static void configure_reset_to_factory()
{
input_gpio_cfg_t pushbutton_reset_to_factory = {
.gpio = board_button_2(),
.type = GPIO_ACTIVE_LOW
};
push_button_set_cb(pushbutton_reset_to_factory,
device_reset_to_factory_cb,
RESET_TO_FACTORY_TIMEOUT, 0, NULL);
}
/* callback function invoked when pushbutton_a is pressed */
static void pushbutton_a_cb()
{
if (pushbutton_a_count_prev == pushbutton_a_count)
pushbutton_a_count++;
}
/* callback function invoked when pushbutton_b is pressed */
static void pushbutton_b_cb()
{
if (pushbutton_b_count_prev == pushbutton_b_count)
pushbutton_b_count++;
}
/* Configure led and pushbuttons with callback functions */
static void configure_led_and_button()
{
/* respective GPIO pins for pushbuttons and leds are defined in
* board file.
*/
input_gpio_cfg_t pushbutton_a = {
.gpio = board_button_1(),
.type = GPIO_ACTIVE_LOW
};
input_gpio_cfg_t pushbutton_b = {
.gpio = board_button_2(),
.type = GPIO_ACTIVE_LOW
};
led_1 = board_led_1();
push_button_set_cb(pushbutton_a,
pushbutton_a_cb,
100, 0, NULL);
push_button_set_cb(pushbutton_b,
pushbutton_b_cb,
100, 0, NULL);
}
static char client_cert_buffer[AWS_PUB_CERT_SIZE];
static char private_key_buffer[AWS_PRIV_KEY_SIZE];
#define THING_LEN 126
#define REGION_LEN 16
static char thing_name[THING_LEN];
static char client_id[MAX_SIZE_OF_UNIQUE_CLIENT_ID_BYTES];
/*---------------------------------------------------------------------------*/
/* populate aws shadow configuration details */
static int aws_starter_load_configuration(ShadowParameters_t *sp)
{
int ret = WM_SUCCESS;
char region[REGION_LEN];
uint8_t device_mac[MAX_MAC_BYTES];
memset(region, 0, sizeof(region));
/* read configured thing name from the persistent memory */
ret = read_aws_thing(thing_name, THING_LEN);
if (ret != WM_SUCCESS) {
wmprintf("Failed to configure thing. Returning!\r\n");
return -WM_FAIL;
}
sp->pMyThingName = thing_name;
/* read device MAC address */
ret = read_aws_device_mac(device_mac);
if (ret != WM_SUCCESS) {
wmprintf("Failed to read device mac address. Returning!\r\n");
return -WM_FAIL;
}
/* Unique client ID in the format prefix-6 byte MAC address */
snprintf(client_id, MAX_SIZE_OF_UNIQUE_CLIENT_ID_BYTES,
"%s-%02x%02x%02x%02x%02x%02x", AWS_IOT_MQTT_CLIENT_ID,
device_mac[0], device_mac[1], device_mac[2],
device_mac[3], device_mac[4], device_mac[5]);
sp->pMqttClientId = client_id;
/* read configured region name from the persistent memory */
ret = read_aws_region(region, REGION_LEN);
if (ret == WM_SUCCESS) {
snprintf(url, sizeof(url), "data.iot.%s.amazonaws.com",
region);
} else {
snprintf(url, sizeof(url), "data.iot.%s.amazonaws.com",
AWS_IOT_MY_REGION_NAME);
}
sp->pHost = url;
sp->port = AWS_IOT_MQTT_PORT;
sp->pRootCA = rootCA;
/* read configured certificate from the persistent memory */
ret = read_aws_certificate(client_cert_buffer, AWS_PUB_CERT_SIZE);
if (ret != WM_SUCCESS) {
wmprintf("Failed to configure certificate. Returning!\r\n");
return -WM_FAIL;
}
sp->pClientCRT = client_cert_buffer;
/* read configured private key from the persistent memory */
ret = read_aws_key(private_key_buffer, AWS_PRIV_KEY_SIZE);
if (ret != WM_SUCCESS) {
wmprintf("Failed to configure key. Returning!\r\n");
return -WM_FAIL;
}
sp->pClientKey = private_key_buffer;
return ret;
}
/*-------------------------------------------------------------------------*/
void shadow_update_status_cb(const char *pThingName, ShadowActions_t action,
Shadow_Ack_Status_t status,
const char *pReceivedJsonDocument,
void *pContextData) {
if (status == SHADOW_ACK_TIMEOUT) {
wmprintf("Shadow publish state change timeout occurred\r\n");
} else if (status == SHADOW_ACK_REJECTED) {
wmprintf("Shadow publish state change rejected\r\n");
} else if (status == SHADOW_ACK_ACCEPTED) {
wmprintf("Shadow publish state change accepted\r\n");
}
}
/*----------------------------------------------------------------------------*/
/* This function will get invoked when led state change request is received */
void led_indicator_cb(const char *p_json_string,
uint32_t json_string_datalen,
jsonStruct_t *p_context) {
int state;
if (p_context != NULL) {
state = *(int *)(p_context->pData);
if (state) {
led_on(led_1);
led_1_state = 1;
} else {
led_off(led_1);
led_1_state = 0;
}
}
}
/*----------------------------------------------------------------------------*/
/* Publish thing state to shadow */
int aws_publish_property_state(ShadowParameters_t *sp)
{
char buf_out[BUFSIZE];
char state[BUFSIZE];
char *ptr = state;
int ret = WM_SUCCESS;
memset(state, 0, BUFSIZE);
if (pushbutton_a_count_prev != pushbutton_a_count) {
snprintf(buf_out, BUFSIZE, ",\"%s\":%lu", VAR_BUTTON_A_PROPERTY,
pushbutton_a_count);
strcat(state, buf_out);
pushbutton_a_count_prev = pushbutton_a_count;
}
if (pushbutton_b_count_prev != pushbutton_b_count) {
snprintf(buf_out, BUFSIZE, ",\"%s\":%lu", VAR_BUTTON_B_PROPERTY,
pushbutton_b_count);
strcat(state, buf_out);
pushbutton_b_count_prev = pushbutton_b_count;
}
/* On receiving led state change notification from cloud, change
* the state of the led on the board in callback function and
* publish updated state on configured topic.
*/
if (distance_prev !=distance) {
snprintf(buf_out, BUFSIZE, ",\"%s\":%lu", VAR_ULTRA_PROPERTY,
distance);
strcat(state, buf_out);
distance_prev = distance;
}
if (*ptr == ',')
ptr++;
if (strlen(state)) {
snprintf(buf_out, BUFSIZE, "{\"state\": {\"reported\":{%s}}}",
ptr);
wmprintf("Publishing '%s' to AWS\r\n", buf_out);
/* publish incremented value on pushbutton press on
* configured thing */
ret = aws_iot_shadow_update(&mqtt_client,
sp->pMyThingName,
buf_out,
shadow_update_status_cb,
NULL,
10, true);
}
return ret;
}
/*----------------------application thread------------------------------------*/
static void aws_starter_demo(os_thread_arg_t data)
{
int led_state = 0, ret;
jsonStruct_t led_indicator;
ShadowParameters_t sp;
aws_iot_mqtt_init(&mqtt_client);
ret = aws_starter_load_configuration(&sp);
if (ret != WM_SUCCESS) {
wmprintf("aws shadow configuration failed : %d\r\n", ret);
goto out;
}
ret = aws_iot_shadow_init(&mqtt_client);
if (ret != WM_SUCCESS) {
wmprintf("aws shadow init failed : %d\r\n", ret);
goto out;
}
ret = aws_iot_shadow_connect(&mqtt_client, &sp);
if (ret != WM_SUCCESS) {
wmprintf("aws shadow connect failed : %d\r\n", ret);
goto out;
}
/* indication that device is connected and cloud is started */
led_on(board_led_2());
wmprintf("Cloud Started\r\n");
/* configures property of a thing */
led_indicator.cb = led_indicator_cb;
led_indicator.pData = &led_state;
led_indicator.pKey = "led";
led_indicator.type = SHADOW_JSON_INT8;
/* subscribes to delta topic of the configured thing */
ret = aws_iot_shadow_register_delta(&mqtt_client, &led_indicator);
if (ret != WM_SUCCESS) {
wmprintf("Failed to subscribe to shadow delta %d\r\n", ret);
goto out;
}
while (1) {
/* Implement application logic here */
if (device_state == AWS_RECONNECTED) {
ret = aws_iot_shadow_init(&mqtt_client);
if (ret != WM_SUCCESS) {
wmprintf("aws shadow init failed: "
"%d\r\n", ret);
goto out;
}
ret = aws_iot_shadow_connect(&mqtt_client, &sp);
if (ret != WM_SUCCESS) {
wmprintf("aws shadow reconnect failed: "
"%d\r\n", ret);
goto out;
} else {
device_state = AWS_CONNECTED;
led_on(board_led_2());
ret = aws_iot_shadow_register_delta(
&mqtt_client, &led_indicator);
wmprintf("Reconnected to cloud\r\n");
}
}
aws_iot_shadow_yield(&mqtt_client, 10);
ret = aws_publish_property_state(&sp);
if (ret != WM_SUCCESS)
wmprintf("Sending property failed\r\n");
os_thread_sleep(100);
}
ret = aws_iot_shadow_disconnect(&mqtt_client);
if (NONE_ERROR != ret) {
wmprintf("aws iot shadow error %d\r\n", ret);
}
out:
os_thread_self_complete(NULL);
return;
}
/*----------------------------------------------------------------------------*/
void wlan_event_normal_link_lost(void *data)
{
/* led indication to indicate link loss */
aws_iot_shadow_disconnect(&mqtt_client);
device_state = AWS_DISCONNECTED;
}
void wlan_event_normal_connect_failed(void *data)
{
/* led indication to indicate connect failed */
aws_iot_shadow_disconnect(&mqtt_client);
device_state = AWS_DISCONNECTED;
}
/* This function gets invoked when station interface connects to home AP.
* Network dependent services can be started here.
*/
void wlan_event_normal_connected(void *data)
{
int ret;
/* Default time set to 1 April 2016 */
//time_t time = 1459468800;
wmprintf("Connected successfully to the configured network\r\n");
if (!device_state) {
/* set system time */
wmtime_time_set_posix(1459468800);
/* create cloud thread */
ret = os_thread_create(
/* thread handle */
&aws_starter_thread,
/* thread name */
"awsStarterDemo",
/* entry function */
aws_starter_demo,
/* argument */
0,
/* stack */
&aws_starter_stack,
/* priority */
OS_PRIO_3);
if (ret != WM_SUCCESS) {
wmprintf("Failed to start cloud_thread: %d\r\n", ret);
return;
}
}
if (!device_state)
device_state = AWS_CONNECTED;
else if (device_state == AWS_DISCONNECTED)
device_state = AWS_RECONNECTED;
}
/*--------------------------------------------------------------------------*/
/*
*********************************************************
**** Ultrasonic Sensor H/W Specific code
**********************************************************
*/
/* Basic Sensor IO initialization to be done here
This function will be called only once during sensor registration
*/
int ultrasonic_sensor_init(struct sensor_info *curevent)
{
wmprintf("%s\r\n", __FUNCTION__);
mdev_t *pinmux_dev, *gpio_dev;
/* Initialize pinmux driver */
pinmux_drv_init();
/* Open pinmux driver */
pinmux_dev = pinmux_drv_open("MDEV_PINMUX");
/* Initialize GPIO driver */
gpio_drv_init();
/* Open GPIO driver */
gpio_dev = gpio_drv_open("MDEV_GPIO");
/* Configure GPIO pin function for GPIO connected to LED */
pinmux_drv_setfunc(pinmux_dev, ULTRASONIC_SEN_IO, ULTRASONIC_SEN_IO_GPIO);
pinmux_drv_setfunc(pinmux_dev, ULTRASONIC_SEN_IO_OUT, ULTRASONIC_SEN_IO_GPIO_OUT);
/* Confiugre GPIO pin direction as Input */
gpio_drv_setdir(gpio_dev, ULTRASONIC_SEN_IO, GPIO_INPUT);
gpio_drv_setdir(gpio_dev, ULTRASONIC_SEN_IO_OUT, GPIO_OUTPUT);
/* Close drivers */
pinmux_drv_close(pinmux_dev);
gpio_drv_close(gpio_dev);
#ifdef ULTRASONIC_SENSOR_TEST
check_ultrasonic_sensor();
#endif /* ULTRASONIC_SENSOR_TEST */
return 0;
}
int ultrasonic_sensor_input_scan(struct sensor_info *curevent)
{
int val;
mdev_t *gpio_dev;
unsigned int duration = 0;
unsigned int fduration = 0;
/* Open GPIO driver */
gpio_dev = gpio_drv_open("MDEV_GPIO");
/* Confiugre GPIO pin direction as Input */
gpio_drv_setdir(gpio_dev, ULTRASONIC_SEN_IO_OUT, GPIO_OUTPUT);
/* Ultrosonic distance reading
Send one altrasonic pulse and wait for
its return responce
Then calculate the distance between transmistted
and received input
*/
/* Send a pulse */
gpio_drv_write(gpio_dev, ULTRASONIC_SEN_IO_OUT, 0);
os_thread_sleep(1);
gpio_drv_write(gpio_dev, ULTRASONIC_SEN_IO_OUT, 1);
os_thread_sleep(1);
gpio_drv_write(gpio_dev, ULTRASONIC_SEN_IO_OUT, 0);
/* Confiugre GPIO pin direction as Input */
//gpio_drv_setdir(gpio_dev, ULTRASONIC_SEN_IO, GPIO_INPUT);
/* Check the line is low */
while(1) {
gpio_drv_read(gpio_dev, ULTRASONIC_SEN_IO, &val);
if (!val)
break;
};
/* Check the line is going high */
while(1) {
gpio_drv_read(gpio_dev, ULTRASONIC_SEN_IO, &val);
if (val)
break;
};
duration = os_get_timestamp(); /* start pulse width measurement */
/* Check the line is going low */
while(1) {
gpio_drv_read(gpio_dev, ULTRASONIC_SEN_IO, &val);
if (!val)
break;
};
fduration = os_get_timestamp(); /* stop pulse width measurement */
if (fduration > duration) {
duration = fduration - duration; /* distance in usec */
/* Calibrate distance measured in centimeters */
duration /= 29;
duration /= 2;
distance = duration ;
wmprintf("%s sensor reading=%d cm\r\n", __FUNCTION__, duration);
//sprintf(curevent->event_curr_value, "%d", duration);
}
gpio_drv_close(gpio_dev);
return 0;
}
struct sensor_info event_ultrasonic_sensor = {
.property = "ultrasonic",
.init = ultrasonic_sensor_init,
.read = ultrasonic_sensor_input_scan,
};
int ultrasonic_sensor_event_register(void)
{
return sensor_event_register(&event_ultrasonic_sensor);
}
#ifdef ULTRASONIC_SENSOR_TEST
void check_ultrasonic_sensor(void)
{
while(1) {
ultrasonic_sensor_input_scan(&event_ultrasonic_sensor);
os_thread_sleep(1000);
}
}
#endif /* ULTRASONIC_SENSOR_TEST */
/*--------------------------------------------------------------------------*/
int main(void)
{
int count = 0;
ultrasonic_sensor_init(&event_ultrasonic_sensor);
/* initialize the standard input output facility over uart */
if (wmstdio_init(UART0_ID, 0) != WM_SUCCESS) {
return -WM_FAIL;
}
/* initialize gpio driver */
if (gpio_drv_init() != WM_SUCCESS) {
wmprintf("gpio_drv_init failed\r\n");
return -WM_FAIL;
}
wmprintf("Build Time: " __DATE__ " " __TIME__ "\r\n");
wmprintf("\r\n#### AWS STARTER DEMO ####\r\n\r\n");
/* configure pushbutton on device to perform reset to factory */
configure_reset_to_factory();
/* configure led and pushbutton to communicate with cloud */
configure_led_and_button();
/* This api adds aws iot configuration support in web application.
* Configuration details are then stored in persistent memory.
*/
enable_aws_config_support();
/* This api starts micro-AP if device is not configured, else connects
* to configured network stored in persistent memory. Function
* wlan_event_normal_connected() is invoked on successful connection.
*/
wm_wlan_start(MICRO_AP_SSID, MICRO_AP_PASSPHRASE);
/* Initialize console on uart0 */
wmstdio_init(UART0_ID, 0);
wmprintf("ultrasonic sensor :- \r\n");
while (1) {
count++;
ultrasonic_sensor_input_scan(&event_ultrasonic_sensor);
/* Sleep 2 seconds */
os_thread_sleep(os_msec_to_ticks(2000));
}
return 0;
}
Comments