/*
 * statemachine.c
 *
 * A simple state machine enabling a menu driven interface to control power to selected CPU cores
 *
 *
 *  Created on: Jan 4, 2016
 *      Author: shaunc
 *
 *  Versions:
 *      2019.2 -      - WK - 2020/04/28 - removed conditional compile statements suppressing APU0 toggling
 * 	  2015.4 - V0.4 - SC - removed printf statement from waiting for command state.
 *      2015.4 - V0.3 - SC - added the print_status state implementation
 *      2015.4 - V0.2 - WK - added print_status to show what the state machine thinks the power status is
 *      2015.4 - V0.1 - SC - 1/8/2016: First working draft implementation
 */

#include <stdlib.h>
#include <stdio.h>
#include <xparameters.h>
#include <xil_printf.h>
#include <pm_api_sys.h>
#include "platform.h"

// enumerate the various states that the state machine can have
enum states {
	toggle_RPU_1 = 1,
	toggle_APU_0,
	toggle_APU_1,
	toggle_APU_2,
	toggle_APU_3,
	terminate,
	initialize,
	print_menu,
	print_status,
	wait_for_command
};

/*
 * enum states getCommand()
 *
 *    Returns one of the enumerated states indicating which processor should
 *    have its power toggled.
 *    RPU0 - no entry (must continue running otherwise user interface disappears)
 *           (future: run self-shutdown to awake 10 seconds later using timer)
 *      1: RPU1
 *    2-5: APUs 1-4
 *      *: displays menu
 *      -: terminates application
 *
 *   Note: The call to inbyte() which returns a character from the UART is a
 *          BLOCKING call which means that execution will stall here until a
 *          character is received.
 *
 *   History:
 *      2015.4 - V0.2 - WK - added print_status to show what the state machine thinks the power status is
 *      2015.4 - V0.1 - SC - initial coding
 *
 */
enum states getCommand() {
	// retrieve a character from the UART
	char c = inbyte();// blocking call to read a single character from the UART

	// based on the character just read, decide what to do
	switch (c) {
	case '1':
		return toggle_RPU_1;
	case '2':
		return toggle_APU_0;
	case '3':
		return toggle_APU_1;
	case '4':
		return toggle_APU_2;
	case '5':
		return toggle_APU_3;
	case '*':
		return print_menu;
	case '-':
		return terminate;
	case '?':
		return print_status;
	default:
		return wait_for_command;
	}
}

/*
 * statemachine()
 *
 * Implements the state machine that regulates messages to the PMU requesting
 * which processors get powered up and powered down.
 *
 *   History:
 *      2015.4 - V1.0 - SC - initial coding
 *
 */

// question - is finish even necessary? Why not have an infinite loop and the "breaks" will cause the exit
void statemachine() {
	// define local variables
	static enum states currentState = initialize;// start the state machine in the initialize state
	int finish = 0;

	// let the user know that the state machine routine was just entered
	printf("\r\n\r\nEntering State Machine \n");

	while (!finish) {
		switch (currentState) {	// based on the current state, decide what to do...
		case initialize:
			ccInit();
			currentState = print_menu;
			break;
		case print_menu:
			printf("\r\nMenu\r\n");
			printf("1: Toggle RPU_1 \n");
			printf("2: Toggle APU_0 \n");
			printf("3: Toggle APU_1 \n");
			printf("4: Toggle APU_2 \n");
			printf("5: Toggle APU_3 \n");
			printf("*: Print Menu Again \n");
			printf("?: Print Status \n");
			printf("-: Exit \n");
			currentState = wait_for_command;// now that the user knows what is available, wait for user command
			break;
		case wait_for_command:
			currentState = getCommand();			// now look for the command
			// this point reached only after something was received by the UART
			break;
		case toggle_APU_0:
			printf("***Toggling APU_0***\n");
			ccToggleApu0();
			currentState = wait_for_command;
			break;
		case toggle_APU_1:
			printf("***Toggling APU_1***\n");
			ccToggleApu1();
			currentState = wait_for_command;
			break;
		case toggle_APU_2:
			printf("***Toggling APU_2***\n");
			ccToggleApu2();
			currentState = wait_for_command;
			break;
		case toggle_APU_3:
			printf("***Toggling APU_3***\n");
			ccToggleApu3();
			currentState = wait_for_command;
			break;
		case toggle_RPU_1:
			printf("***Toggling RPU_1***\n");
			ccToggleRpu1();
			currentState = wait_for_command;
			break;
		case print_status:
			printf("***Processing Units Status***\n");
			xil_printf("%s", ccPowerStatus());
			currentState = wait_for_command;
			break;
		case terminate:
			printf("***Terminating \n");
			ccPowerDownAll();
			finish = 1;
			break;
		default:
			printf("***Should not be here, terminating \n");
			finish = 1;
			break;
		}
	}
	printf("Exiting State Machine\n");
}

//<copyright-disclaimer-start>
//  **************************************************************************************************************
//  * © 2024 Advanced Micro Devices, Inc. All rights reserved.                                                   *
//  * DISCLAIMER                                                                                                 *
//  * The information contained herein is for informational purposes only, and is subject to change              *
//  * without notice. While every precaution has been taken in the preparation of this document, it              *
//  * may contain technical inaccuracies, omissions and typographical errors, and AMD is under no                *
//  * obligation to update or otherwise correct this information.  Advanced Micro Devices, Inc. makes            *
//  * no representations or warranties with respect to the accuracy or completeness of the contents of           *
//  * this document, and assumes no liability of any kind, including the implied warranties of noninfringement,  *
//  * merchantability or fitness for particular purposes, with respect to the operation or use of AMD            *
//  * hardware, software or other products described herein.  No license, including implied or                   *
//  * arising by estoppel, to any intellectual property rights is granted by this document.  Terms and           *
//  * limitations applicable to the purchase or use of AMD’s products are as set forth in a signed agreement     *
//  * between the parties or in AMD's Standard Terms and Conditions of Sale. GD-18                               *
//  *                                                                                                            *
//  **************************************************************************************************************
//<copyright-disclaimer-end>
