saurabh gindeYash RaoDeepak Patel
Published © MIT

Too Close For Comfort

Interface an ultrasonic sensor with MW302 powered by AWS. Want to check if doors are left open or if someone is trespassing? This is it!

BeginnerShowcase (no instructions)3 hours755
Too Close For Comfort

Things used in this project

Hardware components

Marvell MW302 IoT Starter Kit
Marvell MW302 IoT Starter Kit
×1
Ultrasonic Sensor - HC-SR04 (Generic)
Ultrasonic Sensor - HC-SR04 (Generic)
×1

Software apps and online services

AWS SNS
Amazon Web Services AWS SNS
AWS IoT
Amazon Web Services AWS IoT

Story

Read more

Code

ULTRASONIC INTERFACING WITH MW302

C/C++
/*
 * 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;
}

Credits

saurabh ginde

saurabh ginde

1 project • 1 follower
im a hobbyist and love to play with new stuff .
Yash Rao

Yash Rao

1 project • 2 followers
Deepak Patel

Deepak Patel

1 project • 2 followers
Embedded enthusiast, learning iot....

Comments

Add projectSign up / Login