Dependencies:   MQTT

AccCar.cpp

Committer:
micallef25
Date:
2019-12-12
Revision:
7:fd8e0604faaa
Parent:
6:6cb13ac483e0

File content as of revision 7:fd8e0604faaa:

#include "mbed.h"
#include "AccCar.h"
#include "mqtt.h"
#include <stdlib.h>
#include <algorithm>

// ACC macros
#define TICK 1000
#define MONITOR_DIST 17
#define SAFETY_GAP 2

//#define DEBUG_ACC
#define ACC_TAG "[ACC] "
#define ERROR_TAG "[ERROR] "
// speed for a legal stop
#define STOPPED_SPEED 0

AccCar::AccCar(int id, Road* road, int flag, mqtt* singleton)
{
    this->car_id = id;
    this->road = road;
    this->flag = flag;
    this->lead = false;
    this->thread = NULL;
    this->state = NORMAL_STATE;
    this->waited = false;
    this->cycles = 0;
    this->position = 0;
    this->target_speed = 0;
    this->speed = 0;
    this->wait_time = 0;
    this->msg = new position_msg_t;
    this->singleton = singleton;
}

void AccCar::make_position_msg(position_msg_t* msg)
{
    assert(msg != NULL);
    msg->position = this->position;
    msg->speed = this->speed;
    msg->car_id = this->car_id;
    msg->road_id = this->road->get_road_id(); 
    msg->counter = this->road->get_road_clock();
    //msg->state = this->state; 
}

// if a null pointer is sent this means no car is in front and it is the lead car.
// this makes the update section slightly different
void AccCar::set_forward_car(AccCar* car)
{
    if(car == NULL) {
        lead = true;
    } else {
        this->forward_car = car;
        lead = false;
    }
}

// update your speed based on forward car
// unless you are lead car then just mozy on
void AccCar::update_speed()
{
    if( !lead )
    {
        if (forward_car->position - position < MONITOR_DIST) {
            road->done_flags.wait_all(forward_car->flag, osWaitForever, false);

            int diff = forward_car->position - position;
            int maxSafeSpeed = diff - SAFETY_GAP;
            speed = std::min(maxSafeSpeed, target_speed);
            //if(speed < 0)
           // {
             //   printf(ERROR_TAG"f_pos %d pos %d id %d"DELIM,forward_car->position,position,car_id);
            assert(speed >= 0);
            //}
        }   else {
            speed = target_speed;
        }
    }
    else{
        speed = target_speed;    
    }
}

// gets new speed from 5-15
void AccCar::get_new_target_speed()
{
    int temp_speed = 0;
    // get a valid speed 5-15
    temp_speed = rand() %11;
    temp_speed +=5;
    
    this->target_speed = temp_speed;
}

/*
* assuming the car has some way to see a stop sign
* will kick in until a position message with the right ID comes
* which is not implemented
*/
int AccCar::enter_safety_mode()
{
    int old_position = position;
    // using previous speed
    int next_position = position + speed;
    if( old_position < 54 && next_position >= 54 ) 
    {
        // return new speed 0 or 
        return 54 - position;
    }
    return speed;  
}

// update FSM 
void AccCar::update()
{
    while (true) 
    {
        ThisThread::sleep_for(TICK);
        road->go_flags.wait_all(flag);
        cycles++;
#ifndef PUBLISH_ONLY 
        if(cycles > 1)
        {
            // get control msg  
            control_msg_t* c_msg = this->singleton->get_control_msg(this->car_id);
            if(c_msg == NULL)
            {
                // test if we actually have a large delay
               assert(c_msg != NULL);
               speed = enter_safety_mode();
            }
            else{
            //
            // do something with the control message
                assert(c_msg->car_id == car_id );
                if(c_msg->speed > speed){
                    printf(ERROR_TAG" msg speed %d , speed %d car %d"DELIM,c_msg->speed,speed, car_id);
                }
                
                else{
                    // add wait time if we got 0 or something less than our sent speed
                    if(speed == 0 || c_msg->speed < speed)
                    {
                        wait_time++;
                        printf(ACC_TAG"car %d has waited %d"DELIM,car_id,wait_time);
                    }
                    speed = c_msg->speed;
                }
                
                
                //  
                delete c_msg;
            }
        }
#endif

        position = position + speed;
        
        // ensure correctness
        if(!lead){
            //if(position >= this->forward_car->position - 2){
              //  printf(ERROR_TAG"position %d forward pos %d id %d speed %d"DELIM,position,this->forward_car->position, car_id,speed);
                assert(position <= this->forward_car->position - 2);    
           // }
        }
        
        if( (cycles % 5) == 0)
        {
            get_new_target_speed();    
        }
        
        // update position and check intersections
        if( state == NORMAL_STATE ) 
        {
            drive_normal();
        }
        else
        {   
            // case should not happen
            assert(0);
        }
        
//#ifdef DEBUG_ACC
//        printf(ACC_TAG "sending position to server DELIM");
//#endif
        
//#ifdef DEBUG_ACC
//        printf(ACC_TAG "car %d done DELIM",car_id);
//#endif

        // make a message
        make_position_msg(msg);
        
        // stuff a message in the queue
        this->singleton->add_to_position_queue(msg);
        
        // set flag for completion of cycle
        road->done_flags.set(this->flag);
    }
}

void AccCar::reset(int speed)
{
    road->done_flags.clear(flag);

    if (thread != NULL) {
        thread->terminate();
    }


    thread = new Thread();
    assert(thread != NULL);
    thread->start( callback(this, &AccCar::update) );

    this->position = 0;
    this->speed = speed;
    this->target_speed = speed;
}

void AccCar::stop()
{
    if (thread != NULL) {
        thread->terminate();
    }
    delete thread;
    delete msg;
}


// check if we are going to go through an intersection
// and stop or update speed accordingly
void AccCar::drive_normal()
{
    //assert( state == NORMAL_STATE );
    // first update our speed
    if( !lead ) 
    {
        update_speed();
    } else 
    {
        speed = target_speed;
    }
}

int AccCar::get_car_id()
{
    return car_id;
}

int AccCar::get_cycles()
{
    return cycles;
}

int AccCar::get_target_speed()
{
    return target_speed;
}