Unfortunately, due to the rain, many clothes placed outside on the balcony during the days get wet, forcing people to have to rewash them or have to wait a long time to have them dry. The Smart Drying Rack was born as an idea to solve this problem. A small drying rack (easily enlarged to accommodate many more clothes) which, thanks to a rain sensor and small DC motors, can return to a covered position to preserve the clothes.
To create a first version of the device I used some wooden bars as a base (easily replaceable with waterproof wood or plastic) on which 4 HCSR04 sensors are mounted which have the task of scanning the surrounding area and preventing the device from hitting of obstacles. Two Iron Bars are connected to the base (plus a third to attach clothes) which allow it to be connected to the Rain sensor I built. This sensor has the task of detecting the presence of rainwater based on conductivity and an electric transistor. To move the device I used two 12 V DC motors controlled by an L298N module which allow you to easily control the device and make it rotate on itself. The PSOC 62S2 is fundamental which, thanks to its pins, allows you to control everything quickly and easily. Furthermore, Wi-Fii / Bluetooth connectivity allows the development of versions of the Smart Drying Rack that predict the arrival of rain in advance, also alerting the user.
To build a Rain Sensor suitable for this project I used simple but very effective materials. The Sensor is based on a 30x3 cm wooden base. The conductive copper tape was glued on top in two lines separated by a small space of 1 mm. In this way, when a drop of rain touches the sensor, it will allow the passage of current from one side of the tape to the other, generating a pulse that will be read by the Transistor which will send a Digital message to a Pin of the PSOC.
The SS8050 Transistor is connected on one side to the 3.3V of the PSOC6 and on the other to the Digital pin D11 of the PSOC set as INPUT Pin. The passage of the voltage is decided by the rain sensor that we talked about previously which has an connection to the 3.3V and another to the central pin of the Transistor.
If desired, it is also possible to detect the quantity of rainwater thanks to the analog reading of the sensor.
L289N DC MOTORThis is the general outline. The two DC motors (Left and Right) are connected to the L289N module. The module allows you to control the motors via 12V which it recovers from the converter which also powers the PSOC. To manage the motors, the Left and Right enable pins of the L289N are connected to 5V, while the int 1-2 left and int 3-4 right are connected to the PSOCas follows: ENB - 5VINT1 - D7INT2 - D6INT3 - D5INT4 - D4
HCSR04The Smart Drying Rack is equipped with 4 HC SR04 which allow it to avoid obstacles while looking for a covered place. These are very economical and effective Ultrasonic sensors.
As can be seen from this small drawing, the device has a sensor placed forward (1), one placed towards the left side (2), one placed towards the back (3) and finally one placed towards the right (4).
HCSR04 (1) :VCC- 5V / GND-GND / TRIG.-D9 / ECHO-D8HCSR04 (2) :VCC- 5V / GND-GND / TRIG.-A0 / ECHO-A1HCSR04 (3) :VCC- 5V / GND-GND / TRIG.-D10 / ECHO-D11HCSR04 (4) :VCC- 5V / GND-GND / TRIG.-D2 / ECHO-D3
To power the device I used a Heemol 24V 12V to 5V 5A step down module DC-DC Buck Converter which allows you to connect either the PSOC6 via USB connection or via 5V and also allows you to use the same 12V to power the motors.
If desired, it is possible to connect a 12V battery to make the device totally autonomous (But in this case I used a simple 12V connection).
The StructureThe structure of the device is based on two wooden planes. All the electronics are mounted on the 30x10 cm Base, thanks to small holes for M3 screws and 3D printed supports. In fact, all four HCSR04s are attached to the base via a 3D printed support (PLA) [HCSR04 CASE.stl]. The HCSR04 (2 and 4) are placed perfectly central at 15 cm. The two DC motors are also fixed via a support that has two holes for M3 screws [MOTOR DC CASE.stl]. The L289N is secured via two M3 screws and placed at the rear of the base between the two motors. The PSOC6 and the power converter are fixed using cable ties to the base and secured with M3 screws.
Under the base, 2cm from the edge, there is the third wheel fixed with two M3 screws which moves by inertia. This can also be 3D printed [ThirdWheels.stl] or as in my case, recovered from old games.
About 1.75 cm from the edge of the base there are holes to attach the iron bars which allow you to contain the rain sensor and the structure for placing clothes on.
To program the device I used Modustoolbox, which thanks to the C code allowed me to animate my device.
HCSR04's code
To use the HC SR04 sensors I have developed a library that allows me to read the distance reported in (int) format and use it directly.
HCSR04.h
/*
* HCSR04.h
*
* Created on: 9 ago 2023
* Author: pasquale
*/
#ifndef HCSR04_H_
#define HCSR04_H_
#define TIMER_FREQ_HZ 1000000UL
extern char TRIGGER_Pin;
extern char ECHO_Pin;
extern void HCSR04_config();
extern int HCSR04_getdistance();
#endif /* HCSR04_H_ */
HCSR04.c
#include "HCSR04.h"
#include"cyhal.h"
#include "cybsp.h"
#define TIMER_FREQ_HZ 1000000UL
cyhal_timer_t timer;
cyhal_timer_cfg_t timer_cfg = {
.period = 50000,
.is_continuous = true,
.direction = CYHAL_TIMER_DIR_UP,
.compare_value = 0xFFFFFFFF,
.value = 0
};
uint32_t start, end, duration, distance;
void HCSR04_config(TRIGGER_Pin,ECHO_Pin){
cyhal_gpio_init(TRIGGER_Pin, CYHAL_GPIO_DIR_OUTPUT, CYHAL_GPIO_DRIVE_STRONG, CYBSP_LED_STATE_OFF);
cyhal_gpio_init(ECHO_Pin, CYHAL_GPIO_DIR_INPUT, CYHAL_GPIO_DRIVE_NONE,CYBSP_BTN_OFF);
cyhal_timer_init(&timer, NC, NULL);
cyhal_timer_configure(&timer, &timer_cfg);
cyhal_timer_start(&timer);
}
int HCSR04_getdistance(TRIGGER_Pin,ECHO_Pin){
cyhal_gpio_write(TRIGGER_Pin, 1);
Cy_SysLib_DelayUs(10);
cyhal_gpio_write(TRIGGER_Pin, 0);
while (!cyhal_gpio_read(ECHO_Pin));
start = cyhal_timer_read(&timer);
while (cyhal_gpio_read(ECHO_Pin));
end = cyhal_timer_read(&timer);
duration = end - start;
int distance = (duration * 34300) / (2 * TIMER_FREQ_HZ);
return distance;
}
In this HCSR04.h library there are two main functions:
- HCSR04.config() where the ECHO and TRIGGER pins are defined and configured.
- HCSR04_getdistance() which returns an int of the distance detected thanks to ultrasound.
The HCSR04_getdistance function is very simple. First it turns on the TRIGGER pin, defined as output, for 10 microseconds, then it deactivates TRIGGER and activates ECHO defined as input. Finally, it uses a timer to calculate the time it takes for the ultrasound to be detected by ECHO and calculates the distance in cm.
L289N's Code
to control the two DC motors I wrote a simple void motor() function preceded by the declaration of the four INT pins of the module. The L289N works very simply. It is divided into two parts, INT 1-2 for the left engine and INT 3-4 for the right one. If both INTs of a motor are on or off the motor will not move. While if one of the two is on, depending on the motor connection, it will move clockwise or anti-clockwise.
void motor() - main.c
void motor(char* name_motor,char* state,int time){
if (time == 0){
time = 4000;
}
if (strcmp(name_motor, "L")==0){
if(strcmp(state,"BACK")==0){
cyhal_gpio_write(ML_1,false); // ML AVANTI
cyhal_gpio_write(ML_2,true);
} else if (strcmp(state,"FOR")==0){
cyhal_gpio_write(ML_1,false); // ML INDIETRO
cyhal_gpio_write(ML_2,true);
} else if (strcmp(state,"STOP")==0){
cyhal_gpio_write(ML_1,false); // ML STOP
cyhal_gpio_write(ML_2,false);
}
}else if(strcmp(name_motor, "R")==0){
if(strcmp(state,"BACK")==0){
cyhal_gpio_write(MR_1,false); // MR AVANTI
cyhal_gpio_write(MR_2,true);
} else if (strcmp(state,"FOR")==0){
cyhal_gpio_write(MR_1,true); // MR INDIETRO
cyhal_gpio_write(MR_2,false);
}else if (strcmp(state,"STOP")==0){
cyhal_gpio_write(MR_1,false); // MR STOP
cyhal_gpio_write(MR_2,false);
}
}else if (strcmp(name_motor, "L+R")==0){
if(strcmp(state,"RIGHT")==0){
cyhal_gpio_write(MR_1,false); // MR AVANTI
cyhal_gpio_write(MR_2,true);
cyhal_gpio_write(ML_1,false); // ML INDIETRO
cyhal_gpio_write(ML_2,true);
Cy_SysLib_Delay(time);
cyhal_gpio_write(MR_1,false); // MR STOP
cyhal_gpio_write(MR_2,false);
cyhal_gpio_write(ML_1,false); // ML STOP
cyhal_gpio_write(ML_2,false);
} else if (strcmp(state,"LEFT")==0){
cyhal_gpio_write(ML_1,false); // ML AVANTI
cyhal_gpio_write(ML_2,true);
cyhal_gpio_write(MR_1,true); // MR INDIETRO
cyhal_gpio_write(MR_2,false);
Cy_SysLib_Delay(time);
cyhal_gpio_write(MR_1,false); // MR STOP
cyhal_gpio_write(MR_2,false);
cyhal_gpio_write(ML_1,false); // ML STOP
cyhal_gpio_write(ML_2,false);
}
}
}
The function has three arguments: name_motor, state, time. When it is called, it analyzes the name_motor and understands whether the motor you want to continue is L(Left) or R(Right) or both (L+R).
Once the engine has been understood, it analyzes the state variable which is needed to understand whether you want to make the engine go forward (FOR), backward (BACK) or stop (STOP). If instead the motor of interest is (L+R) it analyzes the state variable and understands whether you want to turn left (LEFT) or right (RIGHT). Finally it performs the action by analyzing the rotation time, which if set to 0 makes the rotation last 4000ms approximately 15°
RainSensor's Code
scan_rain() - main.c
bool scan_rain(){
bool state = false;
bool result_scan= false;
result_scan= cyhal_gpio_read(RAIN_SENSOR); // Set Variable
if (result_scan == true){ // First Scan
Cy_SysLib_Delay(1000);
result_scan= cyhal_gpio_read(RAIN_SENSOR);
if (result_scan == true){ // Second Scan
state = true; // Set State to True = Detect Rain
}
}else {
state = false;
}
return state;
}
Finally, the void scanrain which returns a bool, analyzes whether the RAIN_SENSOR pin detects a digital signal, sent by the Transistor. It rescans twice to be sure, and finally returns the value of state as a boolean.
Main()
Now let's analyze int main(). In this function, first the standard pins for UART communication are declared to connect to the terminal (Optional), and then it configures the four HCSR04s as we have already seen in the previous paragraph. Finally in the first part, "setup", configure the pins of the L289N as OUTPUT. In the for(;;) the program constantly analyzes the values detected by the four HCSR04s and writes them to the terminal together with the value detected by the RainSensor. When it detects rain, the system writes "Rain" in the terminal and starts moving according to the position of the obstacles detected by the ultrasonic sensors, looking for a covered place to stop. Rescans every second.
int main(void)
{
cy_rslt_t result = cybsp_init();
if (result != CY_RSLT_SUCCESS) {
CY_ASSERT(0);
}
result = cy_retarget_io_init(CYBSP_DEBUG_UART_TX, CYBSP_DEBUG_UART_RX, CY_RETARGET_IO_BAUDRATE);
printf("\x1b[2J\x1b[;H");
printf("Stendino_Smart!!!\r\n\n");
if (result != CY_RSLT_SUCCESS)
{
CY_ASSERT(0);
}
// CONFIG HCSR04
HCSR04_config(TRIGGER_Pin,ECHO_Pin);
HCSR04_config(TRIGGER2_Pin,ECHO2_Pin);
HCSR04_config(TRIGGER3_Pin,ECHO3_Pin);
HCSR04_config(TRIGGER4_Pin,ECHO4_Pin);
result= cyhal_gpio_init(ML_1, CYHAL_GPIO_DIR_OUTPUT,CYHAL_GPIO_DRIVE_STRONG, false); //ML_1
result= cyhal_gpio_init(ML_2, CYHAL_GPIO_DIR_OUTPUT,CYHAL_GPIO_DRIVE_STRONG, false); //ML_2
result=cyhal_gpio_init(MR_1, CYHAL_GPIO_DIR_OUTPUT,CYHAL_GPIO_DRIVE_STRONG, true); //MR_1
result =cyhal_gpio_init(MR_2, CYHAL_GPIO_DIR_OUTPUT,CYHAL_GPIO_DRIVE_STRONG, true); //MR_2
result =cyhal_gpio_init(RAIN_SENSOR, CYHAL_GPIO_DIR_INPUT,CYHAL_GPIO_DRIVE_NONE, true); //RAINSENSOR
char buffer[50];
motor("L","STOP",0);
motor("R","STOP",0);
for(;;)
{
int distance = HCSR04_getdistance(TRIGGER_Pin,ECHO_Pin);
int distance2 = HCSR04_getdistance(TRIGGER2_Pin,ECHO2_Pin);
int distance3 = HCSR04_getdistance(TRIGGER3_Pin,ECHO3_Pin);
int distance4 = HCSR04_getdistance(TRIGGER4_Pin,ECHO4_Pin);
sprintf(buffer, "HCSR04:[%d/%d/%d/%d]\r\n", distance,distance2,distance3,distance4);
printf(buffer);
sprintf(buffer, "RAINSENSOR:[%d]\r\n", cyhal_gpio_read(RAIN_SENSOR));
printf(buffer);
if (scan_rain() == true){
printf("Rain!!!\r\n\n"); // Print Rain Message in the Terminal
if (distance <= 10){
if(distance4>= 10){
//gira a destra
motor("L+R","RIGHT",0);
}else if (distance2<=10){
//gira a sinistra
motor("L+R","LEFT",0);
}
}else{
motor("L","FOR",0);
motor("R","FOR",0);
}
// torna a B
} else {
motor("L","STOP",0);
motor("R","STOP",0);
}
Cy_SysLib_Delay(1000);
}
}
Future WorkThis is the first version, many technologies are already almost ready for the second version, first of all the dimensions. The V2 will have the dimensions of a typical drying rack to be able to carry many clothes and even heavy weights.
The DC motors will also be replaced by more high-performance motors, 8352 Motor Wheel Brushless Sensored, like those of electric skateboards, which are already being tested. Finally the code will be totally changed. Thanks to the HCSR04 sensors it is possible to develop a scan of your balcony, as with robot vacuum cleaners, the Smart Drying Rack will use the sensors to recognize your position in space. Once the map obtained through scanning and saving in an SD has been created, it will communicate with the user with a TCP server to which it will be possible to connect with a special interface. Once inside it will be possible to select the coverage area, the area where you want the robot to return in case of rain. In fact, every time it detects rain it will scan around and try to reach the rest area while avoiding obstacles.
I leave here a small excerpt of the v2 code for scanning and mapping.
main() v2 (Mapping)
#include "cyhal.h"
#include "cybsp.h"
#include "cy_retarget_io.h"
#include "FS.h"
#include <string.h>
#include "FreeRTOS.h"
#include "task.h"
#include <inttypes.h>
#include <semphr.h>
#include "stdio.h"
#include <stdlib.h>
#include "HCSR04.h"
#define TRIGGER_Pin CYBSP_D6
#define ECHO_Pin CYBSP_D5
#define TRIGGER2_Pin CYBSP_D3
#define ECHO2_Pin CYBSP_D4
#define NUM_BYTES_TO_READ_FROM_FILE (256U)
#define STRING_TO_WRITE "Sto testando i file write"
#define FILE_NAME "MAP.txt"
#define EMFILE_TASK_STACK_SIZE (512U) //512
#define DEBOUNCE_DELAY_MS (50U)
static char file_data[NUM_BYTES_TO_READ_FROM_FILE];
static TaskHandle_t emfile_task_handle;
//static TaskHandle_t read_task;
volatile int uxTopUsedPriority;
U32 volume_size;
U32 num_bytes_to_read;
int error;
FS_FILE *file_ptr;
const char *volume_name = "";
char buffer[70];
char map[]={'0','0','0','0','0','0','0','0','0','0','X','X','X','0','0','0','0','0','0','0','0','0','0'};
char back[]={'0','0','0','0','0','0','0','0','0','0','X','X','X','0','0','0','0','0','0','0','0','0','0'};
int statecode = 0;
SemaphoreHandle_t xSemp;
static void check_error(char *message, int error)
{
if (error < 0)
{
printf("\n================================================================================\n");
printf("\nFAIL: %s\n", message);
printf("Error Value: %d\n", error);
printf("emFile-defined Error Message: %s", FS_ErrorNo2Text(error));
printf("\n================================================================================\n");
while(true);
}
}
//Setup
static void emfile_task()
{
volume_size = FS_GetVolumeSizeKB(volume_name);
printf("Volume size: %"PRIu32" KB\n\n", volume_size);
if(0U == volume_size)
{
printf("Error in checking the volume size\n");
CY_ASSERT(0U);
}
file_ptr = FS_FOpen(FILE_NAME, "w");
if(file_ptr != NULL)
{
volume_size = FS_Write(file_ptr,STRING_TO_WRITE, strlen(STRING_TO_WRITE));
printf("File is written with the following message:\n");
printf("\"%s\"\n\n", STRING_TO_WRITE);
}
error = FS_FClose(file_ptr);
file_ptr = FS_FOpen(FILE_NAME, "r");
if (file_ptr != NULL)
{
/* Last byte is for storing the NULL character. */
num_bytes_to_read = sizeof(file_data) - 1U;
volume_size = FS_GetFileSize(file_ptr);
if(volume_size < num_bytes_to_read)
{
num_bytes_to_read = volume_size;
}
volume_size = FS_Read(file_ptr, file_data, num_bytes_to_read);
if(volume_size != num_bytes_to_read)
{
error = FS_FError(file_ptr);
check_error("Error in reading from the file", error);
}
/* Terminate the string using NULL. */
file_data[num_bytes_to_read] = '\0';
/* Display the file content. */
printf("File Content:\n\"%s\"\n", file_data);
}
error = FS_FClose(file_ptr);
vTaskDelay(pdMS_TO_TICKS(100));
int num = 0;
int val =0;
/*int NumVolumes;
int iVolume;
int BufferSize;
int NumBytesStored;
char acVolumeName [32];
int num = 0;
BufferSize = sizeof (acVolumeName) ;
NumVolumes = FS_GetNumVolumes();
for (iVolume = 0; iVolume < NumVolumes; iVolume++) {
NumBytesStored = FS_GetVolumeName (iVolume, acVolumeName, BufferSize);
if (NumBytesStored < BufferSize) {
printf(acVolumeName) ;
printf("\n");
}
}*/
while(true){
// num++;
//printf("Num = %d\n",num++);
int distance = HCSR04_getdistance(TRIGGER_Pin,ECHO_Pin);
int distance2 = HCSR04_getdistance(TRIGGER2_Pin,ECHO2_Pin);
sprintf(buffer, "[%ld/%d]\r\n", distance,distance2);
file_ptr = FS_FOpen(FILE_NAME, "w");
if(file_ptr != NULL)
{
volume_size = FS_Write(file_ptr,buffer, strlen(buffer));
// printf("File is written with the following message:\n");
val = distance/10;
if (val <= 10) {
for (int v= 0;v <= sizeof(back)/sizeof(back[0]);v++){
map[v]= back[v];
}
int i =9;
i =i - val;
map[i] ='1';
}else {
for (int v= 0;v <= sizeof(back)/sizeof(back[0]);v++){
map[v]= back[v];
}
}
//printf("%d\r\n",map[]);
for (int b=0;b <= sizeof(map)/sizeof(map[0]); b++) {
printf("%c",map[b]);
}
printf("\r\n");
// printf(buffer);
}
else {
printf("ERROR");
}
error = FS_FClose(file_ptr);
vTaskDelay(pdMS_TO_TICKS(1000)); //Delay 1s
}
}
int main(void) //Setup
{
cy_rslt_t result;
FS_Init();
uxTopUsedPriority = configMAX_PRIORITIES - 1;
result = cybsp_init() ;
CY_ASSERT (result == CY_RSLT_SUCCESS);
result = cy_retarget_io_init(CYBSP_DEBUG_UART_TX, CYBSP_DEBUG_UART_RX, CY_RETARGET_IO_BAUDRATE);
CY_ASSERT (result == CY_RSLT_SUCCESS);
__enable_irq();
printf("\x1b[2J\x1b[;H");
printf("************* "
"Start S_S4 "
"************* \n\n");
HCSR04_config(TRIGGER_Pin,ECHO_Pin);
HCSR04_config(TRIGGER2_Pin,ECHO2_Pin);
xTaskCreate(emfile_task, "Task PR", EMFILE_TASK_STACK_SIZE,
NULL, (configMAX_PRIORITIES - 1), &emfile_task_handle);
/* Start the RTOS scheduler. This function should never return */
vTaskStartScheduler();
}
Finally I add a first version of the map transfer via TCP server and the code for a Python interface that is able to read the data sent by the PSOC6 and create a virtual map that allows the user to select the rest point, sending the new position to the psoc which saves it in memory.
A part of tcp_server.c
/******************************************************************************
* File Name: tcp_server.c
*
* /
/* Header file includes */
#include "cyhal.h"
#include "cybsp.h"
#include "cy_retarget_io.h"
/* RTOS header file */
#include "cyabs_rtos.h"
/* Cypress secure socket header file */
#include "cy_secure_sockets.h"
/* Wi-Fi connection manager header files */
#include "cy_wcm.h"
#include "cy_wcm_error.h"
/* Standard C header file */
#include <string.h>
#include <stdint.h>
#include <stdio.h>
/* TCP server task header file. */
#include "tcp_server.h"
/* IP address related header files. */
#include "cy_nw_helper.h"
/* Standard C header files */
#include <inttypes.h>
#include <math.h>
/*******************************************************************************
* Macros
********************************************************************************/
/* To use the Wi-Fi device in AP interface mode, set this macro as '1' */
#define USE_AP_INTERFACE (0)
#define MAKE_IP_PARAMETERS(a, b, c, d) ((((uint32_t) d) << 24) | \
(((uint32_t) c) << 16) | \
(((uint32_t) b) << 8) |\
((uint32_t) a))
#define IP_ADDR_BUFFER_SIZE (20u)
#if(USE_AP_INTERFACE)
#define WIFI_INTERFACE_TYPE CY_WCM_INTERFACE_TYPE_AP
/* SoftAP Credentials: Modify SOFTAP_SSID and SOFTAP_PASSWORD as required */
#define SOFTAP_SSID "MY_SOFT_AP"
#define SOFTAP_PASSWORD "psoc1234"
/* Security type of the SoftAP. See 'cy_wcm_security_t' structure
* in "cy_wcm.h" for more details.
*/
#define SOFTAP_SECURITY_TYPE CY_WCM_SECURITY_WPA2_AES_PSK
#define SOFTAP_IP_ADDRESS_COUNT (2u)
#define SOFTAP_IP_ADDRESS MAKE_IP_PARAMETERS(192, 168, 10, 1)
#define SOFTAP_NETMASK MAKE_IP_PARAMETERS(255, 255, 255, 0)
#define SOFTAP_GATEWAY MAKE_IP_PARAMETERS(192, 168, 10, 1)
#define SOFTAP_RADIO_CHANNEL (1u)
#else
#define WIFI_INTERFACE_TYPE CY_WCM_INTERFACE_TYPE_STA
/* Wi-Fi Credentials: Modify WIFI_SSID, WIFI_PASSWORD, and WIFI_SECURITY_TYPE
* to match your Wi-Fi network credentials.
* Note: Maximum length of the Wi-Fi SSID and password is set to
* CY_WCM_MAX_SSID_LEN and CY_WCM_MAX_PASSPHRASE_LEN as defined in cy_wcm.h file.
*/
#define WIFI_SSID "TIM-95000446"
#define WIFI_PASSWORD "QkXztsNt9T2uNGSFNGTy7EyP"
/* Security type of the Wi-Fi access point. See 'cy_wcm_security_t' structure
* in "cy_wcm.h" for more details.
*/
#define WIFI_SECURITY_TYPE CY_WCM_SECURITY_WPA2_AES_PSK
/* Maximum number of connection retries to a Wi-Fi network. */
#define MAX_WIFI_CONN_RETRIES (10u)
/* Wi-Fi re-connection time interval in milliseconds */
#define WIFI_CONN_RETRY_INTERVAL_MSEC (1000u)
#endif /* USE_AP_INTERFACE */
/* TCP server related macros. */
#define TCP_SERVER_PORT (50007)
#define TCP_SERVER_MAX_PENDING_CONNECTIONS (3u)
#define TCP_SERVER_RECV_TIMEOUT_MS (500u)
#define MAX_TCP_RECV_BUFFER_SIZE (20u)
/* TCP keep alive related macros. */
#define TCP_KEEP_ALIVE_IDLE_TIME_MS (10000u)
#define TCP_KEEP_ALIVE_INTERVAL_MS (1000u)
#define TCP_KEEP_ALIVE_RETRY_COUNT (2u)
/* Length of the LED ON/OFF command issued from the TCP server. */
#define TCP_LED_CMD_LEN (4)
/* LED ON and LED OFF commands. */
#define LED_ON_CMD '1'
#define LED_OFF_CMD '0'
/* Interrupt priority of the user button. */
#define USER_BTN_INTR_PRIORITY (5)
/* Debounce delay for user button. */
#define DEBOUNCE_DELAY_MS (50)
/*******************************************************************************
* Function Prototypes
********************************************************************************/
static cy_rslt_t create_tcp_server_socket(void);
static cy_rslt_t tcp_connection_handler(cy_socket_t socket_handle, void *arg);
static cy_rslt_t tcp_receive_msg_handler(cy_socket_t socket_handle, void *arg);
static cy_rslt_t tcp_disconnection_handler(cy_socket_t socket_handle, void *arg);
static void isr_button_press( void *callback_arg, cyhal_gpio_event_t event);
#if(USE_AP_INTERFACE)
static cy_rslt_t softap_start(void);
#else
static cy_rslt_t connect_to_wifi_ap(void);
#endif /* USE_AP_INTERFACE */
/*******************************************************************************
* Global Variables
********************************************************************************/
/* Secure socket variables. */
cy_socket_sockaddr_t tcp_server_addr, peer_addr;
cy_socket_t server_handle, client_handle;
/* Size of the peer socket address. */
uint32_t peer_addr_len;
/* Flags to track the LED state. */
bool led_state = CYBSP_LED_STATE_OFF;
/* Flag variable to check if TCP client is connected. */
bool client_connected;
cyhal_gpio_callback_data_t cb_data =
{
.callback = isr_button_press,
.callback_arg = NULL
};
/* Queue handler */
extern cy_queue_t led_command_q;
char map_b[]={'0','0','0','0','0','0','0','0','0','0','X','X','X','0','0','0','0','0','0','0','0','0','r','\0'};
char map[]={
'1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','r',
'1','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','B','B','B','1','r',
'1','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','B','S','B','1','r',
'1','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','B','B','B','1','r',
'1','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','1','r',
'1','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','1','r',
'1','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','1','r',
'1','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','1','r',
'1','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','1','r',
'1','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','1','r',
'1','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','1','r',
'1','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','1','r',
'1','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','1','r',
'1','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','1','r',
'1','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','1','r',
'1','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','1','r',
'1','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','1','r',
'1','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','1','r',
'1','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','1','r',
'1','A','A','A','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','1','r',
'1','A','H','A','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','1','r',
'1','A','A','A','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','1','r',
'1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','r','\0'
};
/*******************************************************************************
* Function Name: tcp_server_task
*******************************************************************************
* Summary:
* Task used to establish a connection to a TCP client.
*
* Parameters:
* void *args : Task parameter defined during task creation (unused)
*
* Return:
* void
*
*******************************************************************************/
void position (char targetChar, int *xp, int *yp){
int length = sizeof(map) / sizeof(map[0]);
char alt = 'r';
int x = 0;
int y = 0;
for (int i = 0; i < length; i++) {
if (map[i] != targetChar) {
if (map[i] == alt) {
//printf("Il carattere '%c' è stato trovato alla posizione %d nell'array.\n", targetChar, i);
y++;
x =0;
} else {
x++;
}
} else {
break;
}
}
*xp= x;
*yp=y;
// printf ("X= %d - Y= %d \n",x, y );
}
int dist_a_b(int x_a, int y_a, int x_b , int y_b){
return round(sqrt(fabs(x_b-x_a)*fabs(x_b-x_a) + fabs(x_b-x_a)*fabs(x_b-x_a)));
}
int traiett_a_b (int x_a, int y_a, int x_b , int y_b){
int x_c, y_c,yg;
x_c = x_a;
y_c = y_b;
int ang;
int ma= (y_b-y_a) / (x_b- x_a);
int mb = (y_c-y_a) / (x_c- x_a);
ang = fabs(mb -ma/(1+(mb*ma)));
double gr = atan(ang);
int grad= gr* (180.0/M_PI);
return grad;
}
void tcp_server_task(void *arg)
{
cy_rslt_t result;
cy_wcm_config_t wifi_config = { .interface = WIFI_INTERFACE_TYPE };
/* Variable to store number of bytes sent over TCP socket. */
uint32_t bytes_sent = 0;
/* Variable to receive LED ON/OFF command from the user button ISR. */
uint32_t led_state_cmd = LED_OFF_CMD;
/* Initialize the user button (CYBSP_USER_BTN) and register interrupt on falling edge. */
/* Initialize Wi-Fi connection manager. */
result = cy_wcm_init(&wifi_config);
if (result != CY_RSLT_SUCCESS)
{
printf("Wi-Fi Connection Manager initialization failed! Error code: 0x%08"PRIx32"\n", (uint32_t)result);
CY_ASSERT(0);
}
printf("Wi-Fi Connection Manager initialized.\r\n");
#if(USE_AP_INTERFACE)
/* Start the Wi-Fi device as a Soft AP interface. */
result = softap_start();
if (result != CY_RSLT_SUCCESS)
{
printf("Failed to Start Soft AP! Error code: 0x%08"PRIx32"\n", (uint32_t)result);
CY_ASSERT(0);
}
#else
/* Connect to Wi-Fi AP */
result = connect_to_wifi_ap();
if(result != CY_RSLT_SUCCESS )
{
printf("\n Failed to connect to Wi-Fi AP! Error code: 0x%08"PRIx32"\n", (uint32_t)result);
CY_ASSERT(0);
}
#endif /* USE_AP_INTERFACE */
/* Initialize secure socket library. */
result = cy_socket_init();
if (result != CY_RSLT_SUCCESS)
{
printf("Secure Socket initialization failed! Error code: 0x%08"PRIx32"\n", (uint32_t)result);
CY_ASSERT(0);
}
printf("Secure Socket initialized\n");
/* Create TCP server socket. */
result = create_tcp_server_socket();
if (result != CY_RSLT_SUCCESS)
{
printf("Failed to create socket! Error code: 0x%08"PRIx32"\n", (uint32_t)result);
CY_ASSERT(0);
}
/* Start listening on the TCP server socket. */
result = cy_socket_listen(server_handle, TCP_SERVER_MAX_PENDING_CONNECTIONS);
if (result != CY_RSLT_SUCCESS)
{
cy_socket_delete(server_handle);
printf("cy_socket_listen returned error. Error code: 0x%08"PRIx32"\n", (uint32_t)result);
CY_ASSERT(0);
}
else
{
printf("===============================================================\n");
printf("Listening for incoming TCP client connection on Port: %d\n",
tcp_server_addr.port);
}
char base = '\n';
char string_map[sizeof(map) + 2]; // +1 per il terminatore nullo
int i;
// Copia i caratteri da map a string_map
/* for (i = 0; i < sizeof(map); i++) {
string_map[i] = map[i];
}
// Aggiungi il terminatore nullo per formare una stringa valida
string_map[i] = '\0';
string_map[i+1] = '\n';*/
// Stampa la stringa risultante
// printf("String map: %s\n", string_map);
int count_x = 0;
int count_y = 0;
char targetChar = 'r';
char targetChar2 = '\0';
int length = sizeof(map) / sizeof(map[0]);
for (int i = 0; i < length; i++) {
if (map[i] == targetChar) {
//printf("Il carattere '%c' è stato trovato alla posizione %d nell'array.\n", targetChar, i);
count_y= count_y +1;
if (map[i+1]!=targetChar2 ){
count_x=0;
}
} else {
count_x= count_x +1;
}
}
count_x--;
printf ("X= %d - Y= %d \n",count_x,count_y );
int x_B, y_B;
char s_char = 'S';
position(s_char, &x_B,&y_B);
printf ("X_B= %d - Y_B= %d \n",x_B,y_B );
int x_A, y_A;
char H_char = 'H';
position(H_char, &x_A,&y_A);
printf ("X_A= %d - Y_A= %d \n",x_A,y_A );
int dist= dist_a_b(x_A,y_A,x_B,y_B);
printf ("Dist=%d \n",dist );
int tratt = traiett_a_b(x_A,y_A,x_B,y_B);
printf (" Traiett=%d \n",tratt );
while(true)
{
/* Wait till user button is pressed to send LED ON/OFF command to TCP client. */
// cy_rtos_get_queue(&led_command_q, &led_state_cmd, CY_RTOS_NEVER_TIMEOUT, false);
/* Disable the GPIO signal falling edge detection until the command is
* sent to the TCP client.
*/
// cyhal_gpio_enable_event(CYBSP_USER_BTN, CYHAL_GPIO_IRQ_FALL, USER_BTN_INTR_PRIORITY, false);
/* Wait till the debounce period of the user button. */
// cy_rtos_delay_milliseconds(DEBOUNCE_DELAY_MS);
/*if(!cyhal_gpio_read(CYBSP_USER_BTN))
{*/
/* Send LED ON/OFF command to TCP client if there is an active
* TCP client connection.
*/
if(client_connected)
{
/* Send the command to TCP client. */
result = cy_socket_send(client_handle, &string_map, strlen(string_map),
CY_SOCKET_FLAGS_NONE, &bytes_sent);
result = cy_socket_send(client_handle, base, strlen(base),
CY_SOCKET_FLAGS_NONE, &bytes_sent);
if(result == CY_RSLT_SUCCESS )
{
if(led_state_cmd == LED_ON_CMD)
{
printf("LED ON command sent to TCP client\n");
}
}
else
{
printf("Failed to send command to client. Error code: 0x%08"PRIx32"\n", (uint32_t)result);
if(result == CY_RSLT_MODULE_SECURE_SOCKETS_CLOSED)
{
/* Disconnect the socket. */
cy_socket_disconnect(client_handle, 0);
/* Delete the socket. */
cy_socket_delete(client_handle);
}
}
vTaskDelay(pdMS_TO_TICKS(1000)); //Delay 1s
//}
}
/* Enable the GPIO signal falling edge detection.
cyhal_gpio_enable_event(CYBSP_USER_BTN, CYHAL_GPIO_IRQ_FALL, USER_BTN_INTR_PRIORITY, true);*/
}
}
#if(!USE_AP_INTERFACE)
/*******************************************************************************
* Function Name: connect_to_wifi_ap()
*******************************************************************************
* Summary:
* Connects to Wi-Fi AP using the user-configured credentials, retries up to a
* configured number of times until the connection succeeds.
*
*******************************************************************************/
static cy_rslt_t connect_to_wifi_ap(void)
{
cy_rslt_t result = CY_RSLT_SUCCESS;
char ip_addr_str[IP_ADDR_BUFFER_SIZE];
/* Variables used by Wi-Fi connection manager.*/
cy_wcm_connect_params_t wifi_conn_param;
cy_wcm_ip_address_t ip_address;
/* IP variable for network utility functions */
cy_nw_ip_address_t nw_ip_addr =
{
.version = NW_IP_IPV4
};
/* Variable to track the number of connection retries to the Wi-Fi AP specified
* by WIFI_SSID macro.
*/
int conn_retries = 0;
/* Set the Wi-Fi SSID, password and security type. */
memset(&wifi_conn_param, 0, sizeof(cy_wcm_connect_params_t));
memcpy(wifi_conn_param.ap_credentials.SSID, WIFI_SSID, sizeof(WIFI_SSID));
memcpy(wifi_conn_param.ap_credentials.password, WIFI_PASSWORD, sizeof(WIFI_PASSWORD));
wifi_conn_param.ap_credentials.security = WIFI_SECURITY_TYPE;
printf("Connecting to Wi-Fi Network: %s\n", WIFI_SSID);
/* Join the Wi-Fi AP. */
for(conn_retries = 0; conn_retries < MAX_WIFI_CONN_RETRIES; conn_retries++ )
{
result = cy_wcm_connect_ap(&wifi_conn_param, &ip_address);
if(result == CY_RSLT_SUCCESS)
{
printf("Successfully connected to Wi-Fi network '%s'.\n",
wifi_conn_param.ap_credentials.SSID);
nw_ip_addr.ip.v4 = ip_address.ip.v4;
cy_nw_ntoa(&nw_ip_addr, ip_addr_str);
printf("IP Address Assigned: %s\n", ip_addr_str);
/* IP address and TCP port number of the TCP server */
tcp_server_addr.ip_address.ip.v4 = ip_address.ip.v4;
tcp_server_addr.ip_address.version = CY_SOCKET_IP_VER_V4;
tcp_server_addr.port = TCP_SERVER_PORT;
return result;
}
printf("Connection to Wi-Fi network failed with error code 0x%08"PRIx32"\n."
"Retrying in %d ms...\n", (uint32_t)result, WIFI_CONN_RETRY_INTERVAL_MSEC);
cy_rtos_delay_milliseconds(WIFI_CONN_RETRY_INTERVAL_MSEC);
}
/* Stop retrying after maximum retry attempts. */
printf("Exceeded maximum Wi-Fi connection attempts\n");
return result;
}
#endif /* USE_AP_INTERFACE */
/*******************************************************************************
* Function Name: create_tcp_server_socket
*******************************************************************************
* Summary:
* Function to create a socket and set the socket options
*
*******************************************************************************/
static cy_rslt_t create_tcp_server_socket(void)
{
cy_rslt_t result;
/* TCP socket receive timeout period. */
uint32_t tcp_recv_timeout = TCP_SERVER_RECV_TIMEOUT_MS;
/* Variables used to set socket options. */
cy_socket_opt_callback_t tcp_receive_option;
cy_socket_opt_callback_t tcp_connection_option;
cy_socket_opt_callback_t tcp_disconnection_option;
/* Create a TCP socket */
result = cy_socket_create(CY_SOCKET_DOMAIN_AF_INET, CY_SOCKET_TYPE_STREAM,
CY_SOCKET_IPPROTO_TCP, &server_handle);
if(result != CY_RSLT_SUCCESS)
{
printf("Failed to create socket! Error code: 0x%08"PRIx32"\n", (uint32_t)result);
return result;
}
/* Set the TCP socket receive timeout period. */
result = cy_socket_setsockopt(server_handle, CY_SOCKET_SOL_SOCKET,
CY_SOCKET_SO_RCVTIMEO, &tcp_recv_timeout,
sizeof(tcp_recv_timeout));
if(result != CY_RSLT_SUCCESS)
{
printf("Set socket option: CY_SOCKET_SO_RCVTIMEO failed\n");
return result;
}
/* Register the callback function to handle connection request from a TCP client. */
tcp_connection_option.callback = tcp_connection_handler;
tcp_connection_option.arg = NULL;
result = cy_socket_setsockopt(server_handle, CY_SOCKET_SOL_SOCKET,
CY_SOCKET_SO_CONNECT_REQUEST_CALLBACK,
&tcp_connection_option, sizeof(cy_socket_opt_callback_t));
if(result != CY_RSLT_SUCCESS)
{
printf("Set socket option: CY_SOCKET_SO_CONNECT_REQUEST_CALLBACK failed\n");
return result;
}
/* Register the callback function to handle messages received from a TCP client. */
tcp_receive_option.callback = tcp_receive_msg_handler;
tcp_receive_option.arg = NULL;
result = cy_socket_setsockopt(server_handle, CY_SOCKET_SOL_SOCKET,
CY_SOCKET_SO_RECEIVE_CALLBACK,
&tcp_receive_option, sizeof(cy_socket_opt_callback_t));
if(result != CY_RSLT_SUCCESS)
{
printf("Set socket option: CY_SOCKET_SO_RECEIVE_CALLBACK failed\n");
return result;
}
/* Register the callback function to handle disconnection. */
tcp_disconnection_option.callback = tcp_disconnection_handler;
tcp_disconnection_option.arg = NULL;
result = cy_socket_setsockopt(server_handle, CY_SOCKET_SOL_SOCKET,
CY_SOCKET_SO_DISCONNECT_CALLBACK,
&tcp_disconnection_option, sizeof(cy_socket_opt_callback_t));
if(result != CY_RSLT_SUCCESS)
{
printf("Set socket option: CY_SOCKET_SO_DISCONNECT_CALLBACK failed\n");
return result;
}
/* Bind the TCP socket created to Server IP address and to TCP port. */
result = cy_socket_bind(server_handle, &tcp_server_addr, sizeof(tcp_server_addr));
if(result != CY_RSLT_SUCCESS)
{
printf("Failed to bind to socket! Error code: 0x%08"PRIx32"\n", (uint32_t)result);
}
return result;
}
/*******************************************************************************
* Function Name: tcp_connection_handler
*******************************************************************************
* Summary:
* Callback function to handle incoming TCP client connection.
*
* Parameters:
* cy_socket_t socket_handle: Connection handle for the TCP server socket
* void *args : Parameter passed on to the function (unused)
*
* Return:
* cy_result result: Result of the operation
*
*******************************************************************************/
static cy_rslt_t tcp_connection_handler(cy_socket_t socket_handle, void *arg)
{
cy_rslt_t result;
char ip_addr_str[IP_ADDR_BUFFER_SIZE];
/* IP variable for network utility functions */
cy_nw_ip_address_t nw_ip_addr =
{
.version = NW_IP_IPV4
};
/* TCP keep alive parameters. */
int keep_alive = 1;
#if defined (COMPONENT_LWIP)
uint32_t keep_alive_interval = TCP_KEEP_ALIVE_INTERVAL_MS;
uint32_t keep_alive_count = TCP_KEEP_ALIVE_RETRY_COUNT;
uint32_t keep_alive_idle_time = TCP_KEEP_ALIVE_IDLE_TIME_MS;
#endif
/* Accept new incoming connection from a TCP client.*/
result = cy_socket_accept(socket_handle, &peer_addr, &peer_addr_len,
&client_handle);
if(result == CY_RSLT_SUCCESS)
{
printf("Incoming TCP connection accepted\n");
nw_ip_addr.ip.v4 = peer_addr.ip_address.ip.v4;
cy_nw_ntoa(&nw_ip_addr, ip_addr_str);
printf("IP Address : %s\n\n", ip_addr_str);
printf("Press the user button to send LED ON/OFF command to the TCP client\n");
#if defined (COMPONENT_LWIP)
/* Set the TCP keep alive interval. */
result = cy_socket_setsockopt(client_handle, CY_SOCKET_SOL_TCP,
CY_SOCKET_SO_TCP_KEEPALIVE_INTERVAL,
&keep_alive_interval, sizeof(keep_alive_interval));
if(result != CY_RSLT_SUCCESS)
{
printf("Set socket option: CY_SOCKET_SO_TCP_KEEPALIVE_INTERVAL failed\n");
return result;
}
/* Set the retry count for TCP keep alive packet. */
result = cy_socket_setsockopt(client_handle, CY_SOCKET_SOL_TCP,
CY_SOCKET_SO_TCP_KEEPALIVE_COUNT,
&keep_alive_count, sizeof(keep_alive_count));
if(result != CY_RSLT_SUCCESS)
{
printf("Set socket option: CY_SOCKET_SO_TCP_KEEPALIVE_COUNT failed\n");
return result;
}
/* Set the network idle time before sending the TCP keep alive packet. */
result = cy_socket_setsockopt(client_handle, CY_SOCKET_SOL_TCP,
CY_SOCKET_SO_TCP_KEEPALIVE_IDLE_TIME,
&keep_alive_idle_time, sizeof(keep_alive_idle_time));
if(result != CY_RSLT_SUCCESS)
{
printf("Set socket option: CY_SOCKET_SO_TCP_KEEPALIVE_IDLE_TIME failed\n");
return result;
}
#endif
/* Enable TCP keep alive. */
result = cy_socket_setsockopt(client_handle, CY_SOCKET_SOL_SOCKET,
CY_SOCKET_SO_TCP_KEEPALIVE_ENABLE,
&keep_alive, sizeof(keep_alive));
if(result != CY_RSLT_SUCCESS)
{
printf("Set socket option: CY_SOCKET_SO_TCP_KEEPALIVE_ENABLE failed\n");
return result;
}
/* Set the client connection flag as true. */
client_connected = true;
}
else
{
printf("Failed to accept incoming client connection. Error code: 0x%08"PRIx32"\n", (uint32_t)result);
printf("===============================================================\n");
printf("Listening for incoming TCP client connection on Port: %d\n",
tcp_server_addr.port);
}
return result;
}
/*******************************************************************************
* Function Name: tcp_receive_msg_handler
*******************************************************************************
* Summary:
* Callback function to handle incoming TCP client messages.
*
* Parameters:
* cy_socket_t socket_handle: Connection handle for the TCP client socket
* void *args : Parameter passed on to the function (unused)
*
* Return:
* cy_result result: Result of the operation
*
*******************************************************************************/
static cy_rslt_t tcp_receive_msg_handler(cy_socket_t socket_handle, void *arg)
{
char message_buffer[MAX_TCP_RECV_BUFFER_SIZE];
cy_rslt_t result;
/* Variable to store number of bytes received from TCP client. */
uint32_t bytes_received = 0;
result = cy_socket_recv(socket_handle, message_buffer, MAX_TCP_RECV_BUFFER_SIZE,
CY_SOCKET_FLAGS_NONE, &bytes_received);
if(result == CY_RSLT_SUCCESS)
{
/* Terminate the received string with '\0'. */
message_buffer[bytes_received] = '\0';
printf("\r\nRicevuto dal Client: %s\n", message_buffer);
/* Set the LED state based on the acknowledgement received from the TCP client. */
if(strcmp(message_buffer, "LED ON ACK") == 0)
{
led_state = CYBSP_LED_STATE_ON;
}
}
else
{
printf("Failed to receive acknowledgement from the TCP client. Error: 0x%08"PRIx32"\n",
(uint32_t)result);
if(result == CY_RSLT_MODULE_SECURE_SOCKETS_CLOSED)
{
/* Disconnect the socket. */
cy_socket_disconnect(socket_handle, 0);
/* Delete the socket. */
cy_socket_delete(socket_handle);
}
}
return result;
}
/*******************************************************************************
* Function Name: tcp_disconnection_handler
*******************************************************************************
* Summary:
* Callback function to handle TCP client disconnection event.
*
* Parameters:
* cy_socket_t socket_handle: Connection handle for the TCP client socket
* void *args : Parameter passed on to the function (unused)
*
* Return:
* cy_result result: Result of the operation
*
*******************************************************************************/
static cy_rslt_t tcp_disconnection_handler(cy_socket_t socket_handle, void *arg)
{
cy_rslt_t result;
/* Disconnect the TCP client. */
result = cy_socket_disconnect(socket_handle, 0);
/* Delete the socket. */
cy_socket_delete(socket_handle);
/* Set the client connection flag as false. */
client_connected = false;
printf("TCP Client disconnected! Please reconnect the TCP Client\n");
printf("===============================================================\n");
printf("Listening for incoming TCP client connection on Port:%d\n",
tcp_server_addr.port);
/* Set the LED state to OFF when the TCP client disconnects. */
led_state = CYBSP_LED_STATE_OFF;
return result;
}
The interface.py
import tkinter as tk
from tkinter import *
from tkinter import ttk
import tkinter.font as tkFont
import os
import time
import customtkinter
from PIL import Image,ImageTk
import socket
from threading import *
global ip_device
global state
global connect_state
global ip_text
global connect_b
global s
global map_g
global count_x
global count_y
global estr_x
global estr_y
global spacing_x
estr_x = 0
estr_y = 0
spacing_x = 0
global mouse_x
global mouse_y
connect_state = 0
count_x = 0
count_y = 0
BUFFER_SIZE = 1024
# IP details for the TCP server
#DEFAULT_IP = ip_device # IP address of the TCP server
DEFAULT_PORT = 50007 # Port of the TCP server
DEFAULT_KEEP_ALIVE = 1 # TCP Keep Alive: 1 - Enable, 0 - Disable
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, DEFAULT_KEEP_ALIVE)
s.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPIDLE, 10)
s.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPINTVL, 1)
s.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPCNT, 2)
window = tk.Tk()
window.geometry("1200x650")
window.title("Stendino_Smart")
canvas = Canvas(window, width=1200, height=650,background="black",bd=0)
state= canvas.create_rectangle(0, 0, 0, 0, fill='gray') # rect MAP
def lett_conf():
global ip_device
config = open("./config/conf.txt","r")
ip_device= config.readline()
ip_device= str(ip_device) #IP
ip_device = ip_device.strip()
config.close()
lett_conf()
def griglie():
width=910
height= 640
spacing = 25
for x in range(0,width,spacing):
canvas.create_line(x,0,x,height,fill="black")
for y in range(0,height,spacing):
canvas.create_line(0,y,width,y,fill="black")
def draw_map():
global connect_state
global map_g
global count_x
global count_y
global estr_x
global estr_y
global spacing_x
if count_x != 0:
x_c = int((36 -count_x) /2) * 25
spacing_x = x_c+25
# x_c = 50
y_c =50
if connect_state == 1:
lenght = int(len(map_g) / len(map_g[0]))
for i in range(0,lenght-1):
if map_g[i] == "1":
# canvas.create_line(x_c,y_c,x_c,y_c+25,fill="blue")
canvas.create_rectangle(x_c, y_c, x_c+25, y_c+25, fill='blue') # rect MAP
x_c = x_c +25
elif map_g[i] == "0":
#canvas.create_rectangle(x_c, y_c, x_c+25, y_c+25, fill='red') # rect MAP
x_c = x_c +25
elif map_g[i] == "B":
canvas.create_rectangle(x_c, y_c, x_c+25, y_c+25, fill='red') # rect MAP
x_c = x_c +25
elif map_g[i] == "S":
canvas.create_rectangle(x_c, y_c, x_c+25, y_c+25, fill='red') # rect MAP
x_c = x_c +25
elif map_g[i] == "A":
canvas.create_rectangle(x_c, y_c, x_c+25, y_c+25, fill='green') # rect MAP
x_c = x_c +25
elif map_g[i] == "H":
canvas.create_rectangle(x_c, y_c, x_c+25, y_c+25, fill='green') # rect MAP
x_c = x_c +25
elif map_g[i] == "r":
#canvas.create_rectangle(x_c, y_c, x_c+25, y_c+25, fill='green') # rect MAP
y_c = y_c +25
x_c = int((36 -count_x) /2)*25
estr_y = y_c
estr_x = x_c-25
def base():
map= canvas.create_rectangle(20, 20, 900, 630, fill='gray') # rect MAP
line_map= canvas.create_line(920,650,920,0,width=3,fill="gray")#Linea di separazione controll - map
griglie()
draw_map()
canvas.pack()
images = [] # to hold the newly created image
base()
def create_rectangle(x1, y1, x2, y2, **kwargs):
global state
state = canvas.delete('all')
base()
if 'alpha' in kwargs:
alpha = int(kwargs.pop('alpha') * 255)
fill = kwargs.pop('fill')
fill = canvas.winfo_rgb(fill) + (alpha,)
image = Image.new('RGBA', (x2-x1, y2-y1), fill)
images.append(ImageTk.PhotoImage(image))
state = canvas.create_image(x1, y1, image=images[-1], anchor='nw')
state= canvas.create_rectangle(x1, y1, x2, y2, **kwargs)
#create_rectangle(0, 0, 0, 0, fill='#800000', alpha=.8)
def motion(event):
global mouse_x
global mouse_y
x,y= event.x,event.y
mouse_x = x
mouse_y= y
global state
#print('{},{}'.format(x,y))
if x<900:
if x>20:
if y>20:
if y<630:
state = canvas.delete(state)
# state= canvas.create_rectangle(x-20, y-20, x+40, y+40, fill="yellow") # rect SELECT
state = create_rectangle(x-25, y-25, x+50, y+50, fill='black', alpha=.5)
canvas.pack()
if (mouse_x+50)<= estr_x:
if (mouse_x-25)>= spacing_x:
if (mouse_y-25)>=75:
if (mouse_y+50)<=estr_y:
state = canvas.delete(state)
# state= canvas.create_rectangle(x-20, y-20, x+40, y+40, fill="yellow") # rect SELECT
state = create_rectangle(x-25, y-25, x+50, y+50, fill='yellow', alpha=.5)
canvas.pack()
def change():
global ip_device
with open('./config/conf.txt', 'w') as f:
line1 = ip_device +"\n"
f.writelines([line1])
f.close()
def click(event):
global mouse_x
global mouse_y
global spacing_x
global estr_x
global estr_y
global state
if (mouse_x+50)<= estr_x:
if (mouse_x-25)>= spacing_x:
if (mouse_y-25)>=75:
if (mouse_y+50)<=estr_y:
print("OK")
q_x = round(mouse_x / 25) - round((36 -count_x) /2)
q_y = round(mouse_y / 25) -1
message = "UP-" + str(q_x) + "/"+ str(q_y)
s.send(message.encode('utf-8'))
state = canvas.delete(state)
base()
recvThr= Thread(target=read)
recvThr.daemon = True
recvThr.start()
# canvas.delete('all')
# read()
#print("click")
ip_text= Text(window,height=1,width=15,background="gray",foreground="black",font=("Arial",15))
ip_text.insert("0.0", ip_device) # TEXTBOX-IP
ip_text.place(x=1000, y=20)
labelsliderneg= tk.Label(window, font=("Arial",15), background = "black", foreground = "white", borderwidth = 0,relief="sunken",text=("IP :"))
labelsliderneg.place(x=950, y=22)
window.update_idletasks()
canvas.pack()
griglie()
window.config(background="black")
window.resizable(False, False)
window.bind('<Motion>',motion)
window.bind('<Button>',click)
def lettura():
global ip_device
global ip_text
text = ip_text.get("1.0", "end")
text = str(text)
text=text.strip()
# print(text)
#print(ip_device)
if ip_device != text:
ip_device = text
window.after(1000,change)
window.after(2500,lettura)
lettura()
connect_b= tk.Label(window,text = "CONNETTI", background = "gray", foreground = "black", font= ("Arial",20), borderwidth = 2)
connect_b.place(x=990,y =590)
connect_b.bind("<Button-1>",lambda e:connectf())
def map_f(map):
global count_x
global count_y
targetChar = 'r'
targetChar2 = '\0'
map=map + '\0'
lenght = int(len(map) / len(map[0]))
for i in range(0,lenght-1):
if map[i] == targetChar:
count_y = count_y +1
if map[i+1]!= targetChar2:
count_x = 0
else:
count_x = count_x +1
print("X:" +str(count_x)+" Y:" +str(count_y) +"\n" )
draw_map()
def read():
global connect_state
global s
global map_g
while True:
if connect_state == 1:
data = s.recv(BUFFER_SIZE)
data = data.decode('utf-8')
map_g= data
if data != 0 :
print("Command from Server:")
#print(data + '\n')
print(map_g+ '\n')
map_f(map_g)
time.sleep(0.5)
def connectf():
global connect_state
global ip_device
global connect_b
global s
global map_g
if connect_state == 0:
try:
s.connect((ip_device, DEFAULT_PORT))
print(ip_device)
print("Connected to TCP Server (IP Address: ", ip_device, "Port: ", DEFAULT_PORT, " )")
#conversion_rule = {0: '0', 1: 'A', 2: 'X'}
connect_b.config(text=" SEND ")
message = 'MAP'
s.send(message.encode('utf-8'))
connect_state=1
time.sleep(1)
recvThr= Thread(target=read)
recvThr.daemon = True
recvThr.start()
except:
connect_state = 0
print("ERROR NELLA CONNESSIONE")
# print("click")
if __name__ == "__main__":
window.mainloop()
Due to lack of time I was unable to include these technologies in version 1 but they will be included in the next version.
P.P.
Comments