Files
TX/source/ports.c

814 lines
16 KiB
C
Raw Normal View History

/*
* ports.c
*
* Created on: Mar 21, 2023
* Author: Keith.Lloyd
*/
/*
* Return accessory associated with voltage read
*/
#include "fsl_spi.h"
#include "pin_mux.h"
#include "board.h"
#include "fsl_debug_console.h"
#include <stdbool.h>
#include <stdint.h>
#include "arm_math.h"
#include "ports.h"
#include "frq.h"
#include "spi.h"
#include "display.h"
#include "utils.h"
#include "adc.h"
#include "mode.h"
#include "psu_ctrl.h"
#include "timer.h"
#include "init.h"
#include "amps.h"
#include "fsl_sctimer.h"
#include "pwm.h"
#include "pwr_level.h"
2025-06-11 10:55:00 -05:00
#include "System/system.h"
#include "usbComms.h"
ACCESSORY_t accy1;
ACCESSORY_t accy2;
uint16_t Port_timer;
uint16_t Taps_adjust_timer;
extern uint8_t Port_changed_flag,Init_Done;
extern uint8_t Port_State[],Cur_Mode,old_freq,Bcast_Pwr_Level,Bcast_LF_Value[],Bcast_HF_Value[],Power_Level;
extern MODE_REC_t mode_Array[MODE_MAX_NUM];
extern uint8_t frequency,Over_Voltage_Flag;
extern FREQUENCY_t freqArray[FREQ_MAX_NUM];
extern volatile uint8_t BC_Duty_Cycle;
extern uint16_t Pot_Value_AB[];
extern uint16_t Pot_Value[];
extern uint8_t Dds_Pot_Val[];
2025-06-11 10:55:00 -05:00
extern SYSTEM_DATA_t sys;
uint8_t whatever;
2025-06-11 10:55:00 -05:00
static int handleBroadcast(ACCESSORY_t *accy)
{
switch (accy->state)
{
case PORT_STATE_INIT:
{
if (accy->initState)
{
USB_SendString("Broadcast initializing...");
accy->stateTimer = sys.systemTime + 2000;
}
if (sys.systemTime >= accy->stateTimer)
{
accy->state = PORT_STATE_RUNNING;
}
2025-06-11 10:55:00 -05:00
break;
}
2025-06-11 10:55:00 -05:00
case PORT_STATE_DEINIT:
{
if (accy->initState)
{
USB_SendString("Broadcast deinitializing...");
accy->stateTimer = sys.systemTime + 2000;
}
if (sys.systemTime >= accy->stateTimer)
{
accy->state = PORT_STATE_STANDBY;
USB_SendString("Broadcast in standby!");
}
2025-06-11 10:55:00 -05:00
break;
}
2025-06-11 10:55:00 -05:00
case PORT_STATE_RUNNING:
{
if (accy->initState)
{
USB_SendString("Broadcast running!");
}
break;
}
2025-06-11 10:55:00 -05:00
default:
return -1;
}
2025-06-11 10:55:00 -05:00
return 0;
}
static int handleClamp(ACCESSORY_t *accy)
{
2025-06-11 10:55:00 -05:00
switch (accy->state)
{
case PORT_STATE_INIT:
{
if (accy->initState)
{
}
2025-06-11 10:55:00 -05:00
break;
}
2025-06-11 10:55:00 -05:00
case PORT_STATE_DEINIT:
accy->state = PORT_STATE_STANDBY;
2025-06-11 10:55:00 -05:00
break;
default:
return -1;
}
2025-06-11 10:55:00 -05:00
return 0;
}
static int handleDirectConnect(ACCESSORY_t *accy)
2025-06-11 10:55:00 -05:00
{
switch (accy->state)
{
case PORT_STATE_INIT:
{
if (accy->initState)
{
accy->stateTimer = sys.systemTime + 2000;
USB_SendString("Direct connect initializing...");
}
if (sys.systemTime >= accy->stateTimer)
{
accy->state = PORT_STATE_RUNNING;
}
2025-06-11 10:55:00 -05:00
break;
}
2025-06-11 10:55:00 -05:00
case PORT_STATE_DEINIT:
accy->state = PORT_STATE_STANDBY;
2025-06-11 10:55:00 -05:00
break;
case PORT_STATE_STANDBY:
break;
case PORT_STATE_RUNNING:
{
if (accy->initState)
{
USB_SendString("Direct connect running!");
}
break;
}
2025-06-11 10:55:00 -05:00
default:
return -1;
}
return 0;
}
static int initAccessory(ACCESSORY_t *accy)
{
accy->state = PORT_STATE_INIT;
accy->initState = true;
//accy->handler(accy);
2025-06-11 10:55:00 -05:00
}
static int deinitAccessory(ACCESSORY_t *accy)
{
if (accy->isConnected)
{
accy->state = PORT_STATE_DEINIT;
accy->initState = true;
}
//accy->handler(accy);
2025-06-11 10:55:00 -05:00
}
void ACCY_service(void)
{
ACCY_Update();
ACCESSORY_t *active = sys.activeAccessory;
// if there is an accessory waiting to be switched, check that the current active is in standby before initializing
if (active != NULL)
{
if (active->isConnected)
{
// service the current accessory
PortState_t prevState = active->state;
active->handler(active);
active->initState = (prevState != active->state);
}
else
{
// active accessory was disconnected
// fall back to induction for now
ACCY_setActive(&sys.ports[ACCY_PORT_INDUCTION], CHANNEL_A);
}
if ((sys.nextAccessory) != NULL)
{
// wait until current accessory has been deinitialized before switching
if (active->state == PORT_STATE_STANDBY)
{
sys.activeAccessory = sys.nextAccessory;
sys.nextAccessory = NULL;
initAccessory(active);
}
}
}
}
void ACCY_next(void)
{
// cycle through accessories and channels to find the next available
AccessoryPortId_t currentPort = sys.activeAccessory->portId;
AccyChannelId_t currentChannel = sys.activeAccessory->activeChannel;
AccessoryPortId_t port = currentPort;
AccyChannelId_t channel = currentChannel + 1;
do
{
if (channel >= NUM_CHANNELS)
{
port++;
if (port >= NUM_PORTS)
{
port = 0;
}
channel = CHANNEL_A;
}
AccessoryChannel_t *ch = &sys.ports[port].channels[channel];
if (ch->connected)
{
ACCY_setActive(&sys.ports[port], channel);
break;
}
channel++;
} while ((port != currentPort) || (channel != currentChannel));
}
void ACCY_setActive(ACCESSORY_t *accy, AccyChannelId_t channel)
{
accy->activeChannel = channel;
// deinitialize current accessory
if (sys.activeAccessory != NULL)
{
deinitAccessory(sys.activeAccessory);
// initialize the accessory to switch when complete
sys.nextAccessory = accy;
}
else
{
// nothing active, switch now
sys.activeAccessory = accy;
initAccessory(sys.activeAccessory);
}
}
void ACCY_Disconnect(ACCESSORY_t *accy)
{
sprintf(sys.tmpString, "Accessory disconnected: %d", accy->connected);
USB_SendString(sys.tmpString);
accy->connected = ID_NONE;
accy->isConnected = false;
accy->handler = NULL;
accy->state = PORT_STATE_STANDBY;
accy->channels[CHANNEL_A].id = CHANNEL_A;
accy->channels[CHANNEL_A].connected = false;
accy->channels[CHANNEL_B].id = CHANNEL_B;
accy->channels[CHANNEL_B].connected = false;
}
// setup the accessory as connected but do not initialize it until set as active
bool ACCY_Connect(ACCESSORY_t *accy, ACCY_ID_t id)
2025-06-11 10:55:00 -05:00
{
accy->connected = id;
accy->isConnected = true;
accy->state = PORT_STATE_STANDBY;
2025-06-11 10:55:00 -05:00
accy->channels[CHANNEL_A].id = CHANNEL_A;
accy->channels[CHANNEL_A].connected = false;
accy->channels[CHANNEL_B].id = CHANNEL_B;
accy->channels[CHANNEL_B].connected = false;
2025-06-11 10:55:00 -05:00
switch (id)
{
case ID_TX_DUAL_DIRECT:
{
accy->channels[CHANNEL_B].connected = true;
// intentional fall through
}
case ID_TX_SINGLE_DIRECT:
{
accy->channels[CHANNEL_A].connected = true;
accy->handler = handleDirectConnect;
2025-06-11 10:55:00 -05:00
break;
}
case ID_CLAMP:
case ID_CLAMP2:
{
accy->channels[CHANNEL_A].connected = true;
2025-06-11 10:55:00 -05:00
accy->handler = handleClamp;
break;
}
case ID_BROADCAST:
{
accy->channels[CHANNEL_A].connected = true;
2025-06-11 10:55:00 -05:00
accy->handler = handleBroadcast;
break;
}
default:
{
accy->handler = NULL;
accy->connected = ID_NONE;
accy->isConnected = false;
}
}
sprintf(sys.tmpString, "New accessory connected: %d", accy->connected);
USB_SendString(sys.tmpString);
return accy->isConnected;
2025-06-11 10:55:00 -05:00
}
static ACCY_ID_t ReadAccessory(uint8_t port)
{
2025-06-11 10:55:00 -05:00
if (port >= NUM_PORTS)
{
return ID_NONE;
}
ACCESSORY_t *accy = &sys.ports[port];
2025-06-11 10:55:00 -05:00
uint32_t idNumber = (uint32_t)((*accy->idVoltage * 3.3333f) + 0.5f); //multiply by 3.3333 and round down to nearest integer
return (ACCY_ID_t)idNumber;
}
void Disconnect(uint8_t port) // called when you disconnect
{
2025-06-11 10:55:00 -05:00
if (port == ACCY_PORT_1)
{
accy1.connected = ID_NONE;
accy1.consecutiveScans = 0;
accy1.isConnected = false;
//Change Mode if this accessory was selected
if(mode_Array[PORT1_A].Selected || mode_Array[PORT1_B].Selected)
{
//disconnect port 1 from keith's struct
mode_Array[PORT1_A].Selected = 0;
mode_Array[PORT1_B].Selected = 0;
if ((Cur_Mode > BROADCAST) && (Cur_Mode ==PORT1_A) || (Cur_Mode == PORT1_B) ) //and change mode
Cur_Mode = Next_Available_Mode(Cur_Mode); // find next Mode available
}
else
{
//disconnect port 1 from keith's struct
mode_Array[PORT1_A].Selected = 0;
mode_Array[PORT1_B].Selected = 0;
}
}
else //port 2
{
accy2.connected = ID_NONE;
accy2.consecutiveScans = 0;
accy2.isConnected = false;
//Change Mode if this accessory was selected
if(mode_Array[PORT2_A].Selected || mode_Array[PORT2_B].Selected)
{
//disconnect port 2 from keith's struct
mode_Array[PORT2_A].Selected = 0;
mode_Array[PORT2_B].Selected = 0;
if ((Cur_Mode > BROADCAST) && (Cur_Mode == PORT2_A) || (Cur_Mode == PORT2_B) ) //and change mode
// Cur_Mode = Next_Available_Mode(Cur_Mode); // find next Mode available
{
if (mode_Array[PORT1_A].Selected || mode_Array[PORT1_B].Selected) //and change mode
Cur_Mode = PORT1_A;
else
Cur_Mode = Next_Available_Mode(Cur_Mode); // find next Mode available
}
//
// else
// Cur_Mode = 1;
// if (Cur_Mode > 0)
// {
// if (mode_Array[1].Selected || mode_Array[2].Selected) //and change mode
// Cur_Mode = 1;
// else
// Cur_Mode = Next_Available_Mode(Cur_Mode); // find next Mode available
// }
}
else
{
//disconnect port 1 from keith's struct
mode_Array[PORT2_A].Selected = 0;
mode_Array[PORT2_B].Selected = 0;
}
}
Port_changed_flag = true; // added 10/2/23
Init_Done = false; // 3/20/24 Force a Power Level One change
//Configure frequency to make sure things are setup correctly
// Tx_ConfigureFrequency();
}
void ACCY_Init(void)
{
2025-06-11 10:55:00 -05:00
for (int i=0; i<NUM_PORTS; ++i)
{
sys.ports[i].connected = ID_NONE;
sys.ports[i].consecutiveScans = 0;
sys.ports[i].isConnected = false;
sys.ports[i].portId = i;
2025-06-11 10:55:00 -05:00
}
sys.ports[ACCY_PORT_1].idVoltage = &sys.adc.V_ID1;
sys.ports[ACCY_PORT_2].idVoltage = &sys.adc.V_ID2;
accy1.connected = ID_NONE;
accy1.consecutiveScans = 0;
accy1.isConnected = false;
accy2.connected = ID_NONE;
accy2.consecutiveScans = 0;
accy2.isConnected = false;
Port_timer = DELAY_100MS;
Port_changed_flag = false;
//Setup accessory for GPIO gain control
// InitAccessoryGainGPIO();
}
2025-06-11 10:55:00 -05:00
void ACCY_Update(void)
{
for (int i=ACCY_PORT_1; i<NUM_PORTS; ++i)
2025-06-11 10:55:00 -05:00
{
ACCESSORY_t *accy = &sys.ports[i];
ACCY_ID_t detected = ReadAccessory(i);
if(!accy->isConnected) //Nothing connected. Look for accessory to connect
2025-06-11 10:55:00 -05:00
{
if((detected == accy->lastDetected) && (detected != ID_NONE)) //If detected same as last time and not ID_NONE
{
if(++accy->consecutiveScans == AC_NUM_SCANS_TO_CONNECT) //Connect on 3rd consecutive scan of same accessory
{
// we found a newly connected accessory. switch to it.
if (ACCY_Connect(accy, detected))
{
ACCY_setActive(accy, CHANNEL_A);
}
2025-06-11 10:55:00 -05:00
}
}
else //If different than last scan
{
accy->lastDetected = detected; //remember what was scanned last time
accy->consecutiveScans = 0;
}
}
else if (detected != accy->connected) //If connected and detected reads different, disconnect
{
ACCY_Disconnect(accy);
2025-06-11 10:55:00 -05:00
}
}
}
//Call @ 10Hz to detect, connect, and disconnect accessories
/*
* Connect accessory
*/
2025-06-11 10:55:00 -05:00
bool ACCY_isKnown(ACCY_ID_t id)
{
bool known = false;
switch(id)
{
case ID_TX_SINGLE_DIRECT:
case ID_TX_DUAL_DIRECT:
case ID_CLAMP:
case ID_CLAMP2:
known = true;
break;
}
return known;
}
ACCY_ID_t ACCY_GetConnectedAccessory(uint8_t port)
{
return ID_NONE;
}
ACCY_ID_t ACCY_GetActive(void)
{
if(Cur_Mode == PORT1_A)
{
return ACCY_GetConnectedAccessory(1);
}
else
{
return ACCY_GetConnectedAccessory(2);
}
}
void Read_Tx_Ports(void) // check for whats plugged in at the ports every 100mS.
{
2025-06-11 10:55:00 -05:00
uint8_t chip;
Port_timer = DELAY_100MS;
2025-06-11 10:55:00 -05:00
ACCY_Update();
}
void Select_Output_Port(void) // which DC Out port, to switch on
{
Port_State[MID_SR] &= OUT_RELAY_OFF_MASK;
if (Cur_Mode != BROADCAST)
{
Delay_Ticks(DELAY_100MS);
2025-06-11 10:55:00 -05:00
if(Compare_Voltage(sys.adc.V_CHK, MAX_BYPASS_VOLTS))
{
2025-06-11 10:55:00 -05:00
sys.status[OVERVOLTAGE] = true;
Select_Bypass(OFF); // Force into blocked state.
Delay_Ticks(20);
}
2025-06-11 10:55:00 -05:00
// HACK
Select_Estop(CONNECTED); // Ensure output is not ISOLATED from connections
switch (Cur_Mode)
{
case PORT1_A:
Port_State[MID_SR] |= PORT1A_ON;
break;
case PORT1_B:
Port_State[MID_SR] |= PORT1B_ON;
break;
case PORT2_A:
Port_State[MID_SR] |= PORT2A_ON;
break;
case PORT2_B:
Port_State[MID_SR] |= PORT2B_ON;
break;
default:
Port_State[MID_SR] |= PORT2B_ON; // TODO Later disconnect??
break;
}
Disable_BC();
Reset_Power_Gain();
Port_changed_flag = false;
SPI0_SendBytes(Port_State, 3, EXPANDER);
}
else
{ // Assumes broadcast mode has just been selected
Disable_DC(); // Shut down Direct connect circuitry
Select_Estop(ISOLATED); // Ensure output is ISOLATED from connections
Tx_ConfigureFrequency(); // Select correct frequency
Enable_BC(); // Enable BCAST circuitry using either Minimum or previously selected freq
Port_changed_flag = false;
}
}
void Reset_Power_Gain(void)
{
Power_Level = 0;
Bcast_Pwr_Level = 0;
// if( (ACCY_GetConnectedAccessory(1) != ID_CLAMP) && (ACCY_GetConnectedAccessory(2) != ID_CLAMP))
if(!Check_For_Clamp())
{
if (freqArray[frequency].frequency1 <= MAX_DTYPE)
Dds_Pot_Val[1] = Pot_Value[Power_Level]; // data
else
Dds_Pot_Val[1] = Pot_Value_AB[Power_Level]; // data
}
else
Get_Clamp_Value();
Dds_Pot_Val[0] = 0; // address
SPI0_SendBytes(Dds_Pot_Val, 2, AMPLITUDE);
Delay_Ticks(30); // Set power out level 1 3/20/24
// Power_Level = 1;
// if(Init_Done)
// {
// Delay_Ticks(10); // Set power out level 1 3/20/24
// Power_Level++;
// inc_pwr();
Init_Done = false;
// }
}
void Tx_ConfigureFrequency(void)
{
uint32_t tmp_frq;
if (freqArray[frequency].bc_enabled == false && Cur_Mode == BROADCAST) // if (freq < min freq) ToDo
{
tmp_frq = Search_BC_Frequency(); // select minimum frequency for BCAST
if (tmp_frq < FREQ_MAX_NUM)
frequency = tmp_frq;
//endif
}
}
uint32_t Search_BC_Frequency(void)
{
uint32_t idx;
idx = 0;
while (freqArray[idx].bc_enabled == false && idx < FREQ_MAX_NUM)
idx++;
if (idx >= FREQ_MAX_NUM)
idx = FREQ_MAX_NUM;
return(idx);
}
uint32_t Search_Frequency(uint32_t pattern)
{
uint32_t idx;
idx = 0;
while (freqArray[idx].frequency1 != pattern && idx < FREQ_MAX_NUM)
idx++;
if (idx >= FREQ_MAX_NUM)
idx = FREQ_MAX_NUM;
return(idx);
}
void Disable_DC(void)
{
All_Amps_Off(); // shut down Amplifiers DC connections
// Shut off all amplifier enables
// Reset_DDS(); // Stop all DDS chips
// Set_PSU_Voltage(V_18V); //MID_POINT_PSU 18,24,27,30,36, 55
// Set PSU to MIN.
}
void Enable_BC(void)
{
// if((freqArray[old_freq].frequency1 >8010 ) && (freqArray[frequency].frequency1 < 8010))
// Cycled_Freq_Change_BC(LF);
// else
// {
// if((freqArray[old_freq].frequency1 < 8010 ) && (freqArray[frequency].frequency1 > 8010))
// Cycled_Freq_Change_BC(HF);
// }
if(freqArray[frequency].frequency1 <= 8010)
BC_Duty_Cycle = Bcast_LF_Value[Bcast_Pwr_Level];
else
BC_Duty_Cycle = Bcast_HF_Value[Bcast_Pwr_Level];
PWM_Setup(freqArray[frequency].frequency1, BC_Duty_Cycle);//freqArray[frequency].frequency1
Port_State[MID_SR] |=ANT_AMP_EN; // Enable Antenna amp
// Port_State[BOTTOM_SR] |= ANT_AMP_PWR; // Enable PWR Switch
Port_State[TOP_SR] |= ANT_AMP_SW;
SPI0_SendBytes(Port_State, 3, EXPANDER); // Update shift register
Delay_Ticks(5);
Set_PSU_Voltage(V_27V); // Set PSU to MAX
Port_State[BOTTOM_SR] &= AMP_PSU_ON; // switch AMP PSU on
SPI0_SendBytes(Port_State, 3, EXPANDER); // Update shift register
}
void Cycled_Freq_Change_BC(uint8_t value)
{
if(value == LF)
{
if(Bcast_Pwr_Level == MAX_BCAST_PWR)
Bcast_Pwr_Level--;
BC_Duty_Cycle = 10;
BC_Duty_Cycle = BC_Duty_Cycle + Bcast_Pwr_Level*5;
}
else
{
BC_Duty_Cycle = 10;
BC_Duty_Cycle = BC_Duty_Cycle + Bcast_Pwr_Level*10;
}
}
void Enable_DC(void)
{
// Switch on correct amplifier enables
// Switch on correct power switches
// Enable correct DDS chips
// Set PSU to Medium.
}
void Disable_BC(void)
{
Port_State[MID_SR] &=~ANT_AMP_EN; // disable Antenna amp
// Port_State[BOTTOM_SR] |=ANT_AMP_PWR; // Enable PWR Switch
Port_State[TOP_SR] &= ~ANT_AMP_SW;
SPI0_SendBytes(Port_State, 3, EXPANDER); // Update shift register
// Change the SCT clock back here
PWM_Setup(15890, 0); // switches off PWM // Set duty cycle to zero
Delay_Ticks(5);
Set_PSU_Voltage(V_24V); // Set PSU to MIN
// Init_PWM_CLKS(DC_CLK); // Return timer clock to internal
}
2025-06-11 10:55:00 -05:00
bool Is_Clamp_Detected(void)
{
if((ACCY_GetConnectedAccessory(1) == ID_CLAMP) || (ACCY_GetConnectedAccessory(2) == ID_CLAMP) || (ACCY_GetConnectedAccessory(1) == ID_CLAMP2) || (ACCY_GetConnectedAccessory(2) == ID_CLAMP2))
return(true);
else
return(false);
}