diff --git a/Bandscope.ino b/Bandscope.ino index 3054841..2f952dc 100644 --- a/Bandscope.ino +++ b/Bandscope.ino @@ -237,14 +237,8 @@ static uint16_t chunkIndex; if ( numberOfWebsocketClients > 0 ) // Start off the json document for the scan { - jsonDocument.clear (); chunkIndex = 0; - - jsonDocument["PreAmp"] = setting.PreampGain; - jsonDocument["mType"] = "chunkSweep"; - jsonDocument["StartIndex"] = 0; - jsonDocument["sweepPoints"] = sweepPoints; - jsonDocument["sweepTime"] = (uint32_t)(sweepMicros/1000); + initChunkSweepDoc (autoSweepStep); Points = jsonDocument.createNestedArray ( "Points" ); // Add Points array jsonDocInitialised = true; } @@ -395,12 +389,8 @@ static uint16_t chunkIndex; if ( ( chunkIndex >= wiFiPoints ) || !jsonDocInitialised ) // Start new jSon document { chunkIndex = 0; - jsonDocument.clear(); - jsonDocument["mType"] = "chunkSweep"; - jsonDocument["StartIndex"] = autoSweepStep; - jsonDocument["sweepPoints"] = sweepPoints; - jsonDocument["sweepTime"] = (uint32_t)(sweepMicros/1000); - Points = jsonDocument.createNestedArray ("Points" ); // Add Points array + initChunkSweepDoc (autoSweepStep); + Points = jsonDocument.createNestedArray ( "Points" ); // Add Points array jsonDocInitialised = true; } } diff --git a/IFsweep.ino b/IFsweep.ino index f91d843..c8e003e 100644 --- a/IFsweep.ino +++ b/IFsweep.ino @@ -120,6 +120,7 @@ static uint16_t chunkIndex; } // initSweep || changedSetting autoSweepStep = 0; // Set the step counter to zero + sweepStep = 0; autoSweepFreq = startFreq_IF; // Set the start frequency. nextPointFreq = autoSweepFreq + autoSweepFreqStep; @@ -142,24 +143,16 @@ static uint16_t chunkIndex; if ( numberOfWebsocketClients > 0 ) // Start off the json document for the scan { - jsonDocument.clear (); chunkIndex = 0; - - jsonDocument["PreAmp"] = setting.PreampGain; // Fixed gain - jsonDocument["mType"] = "chunkSweep"; - jsonDocument["StartIndex"] = 0; - jsonDocument["sweepPoints"] = sweepPoints; - jsonDocument["sweepTime"] = (uint32_t)(sweepMicros/1000); + initChunkSweepDoc (sweepStep); Points = jsonDocument.createNestedArray ( "Points" ); // Add Points array jsonDocInitialised = true; } - else jsonDocInitialised = false; #endif // #ifdef USE_WIFI - sweepStep = 0; startFreq = startFreq_IF + sigFreq_IF; // Start freq for the LO stopFreq = stopFreq_IF + sigFreq_IF; // Stop freq for the LO @@ -315,12 +308,8 @@ static uint16_t chunkIndex; if ( ( chunkIndex >= wiFiPoints ) || !jsonDocInitialised ) // Start new jSon document { chunkIndex = 0; - jsonDocument.clear(); - jsonDocument["mType"] = "chunkSweep"; - jsonDocument["StartIndex"] = sweepStep; - jsonDocument["sweepPoints"] = sweepPoints; - jsonDocument["sweepTime"] = (uint32_t)(sweepMicros/1000); - Points = jsonDocument.createNestedArray ("Points" ); // Add Points array + initChunkSweepDoc (sweepStep); + Points = jsonDocument.createNestedArray ( "Points" ); // Add Points array jsonDocInitialised = true; } } diff --git a/RXsweep.ino b/RXsweep.ino index 0116113..608639e 100644 --- a/RXsweep.ino +++ b/RXsweep.ino @@ -126,6 +126,7 @@ static uint16_t chunkIndex; } // initSweep || changedSetting autoSweepStep = 0; // Set the step counter to zero + sweepStep = 0; autoSweepFreq = startFreq_RX; // Set the start frequency. nextPointFreq = autoSweepFreq + autoSweepFreqStep; @@ -148,24 +149,16 @@ static uint16_t chunkIndex; if ( numberOfWebsocketClients > 0 ) // Start off the json document for the scan { - jsonDocument.clear (); chunkIndex = 0; - - jsonDocument["PreAmp"] = setting.PreampGain; - jsonDocument["mType"] = "chunkSweep"; - jsonDocument["StartIndex"] = 0; - jsonDocument["sweepPoints"] = sweepPoints; - jsonDocument["sweepTime"] = (uint32_t)(sweepMicros/1000); + initChunkSweepDoc (sweepStep); Points = jsonDocument.createNestedArray ( "Points" ); // Add Points array jsonDocInitialised = true; } - else jsonDocInitialised = false; #endif // #ifdef USE_WIFI - sweepStep = 0; startFreq = startFreq_RX; // Start freq for the RX stopFreq = stopFreq_RX; // Stop freq for the RX @@ -322,12 +315,8 @@ static uint16_t chunkIndex; if ( ( chunkIndex >= wiFiPoints ) || !jsonDocInitialised ) // Start new jSon document { chunkIndex = 0; - jsonDocument.clear(); - jsonDocument["mType"] = "chunkSweep"; - jsonDocument["StartIndex"] = sweepStep; - jsonDocument["sweepPoints"] = sweepPoints; - jsonDocument["sweepTime"] = (uint32_t)(sweepMicros/1000); - Points = jsonDocument.createNestedArray ("Points" ); // Add Points array + initChunkSweepDoc (sweepStep); + Points = jsonDocument.createNestedArray ( "Points" ); // Add Points array jsonDocInitialised = true; } } diff --git a/SigLo.ino b/SigLo.ino index d1a5f99..fbfaa7e 100644 --- a/SigLo.ino +++ b/SigLo.ino @@ -107,6 +107,11 @@ void initSigLow() oldFreq = 0; // Force write of frequency on first loop +#ifdef USE_WIFI + if ( numberOfWebsocketClients > 0 ) + pushSigGenSettings (); +#endif + } @@ -119,6 +124,10 @@ void initSigLow() void doSigGenLow () { static uint32_t oldIF; // to store the current IF + static uint16_t oldSigGenOutputOn; + float p; // temporary variable for slider percent + static uint16_t sliderRange = ATTENUATOR_RANGE + RX_SI4432_MAX_DRIVE * 3; + uint16_t t_x = 0, t_y = 0; // To store the touch coordinates @@ -127,6 +136,29 @@ void doSigGenLow () showUpDownButtons = 1; #endif + if (changedSetting) { + // calculate required drive and attenuator settings + // keep drive as high as possible so nasties are attenuated + uint16_t sgRXDrive = RX_SI4432_MAX_DRIVE; + uint16_t attenuation = sigGenSetting.Calibration - sigGenSetting.Power; + if (attenuation > ATTENUATOR_RANGE ) + { + int16_t diff = attenuation - ATTENUATOR_RANGE; + sgRXDrive = RX_SI4432_MAX_DRIVE - (int16_t)( (diff-1)/3 ) - 1 ; + attenuation = ATTENUATOR_RANGE - 2 + (diff-1)%3; + } + SetSGRxDrive(sgRXDrive); + att.SetAtten(attenuation); + Serial.printf("sigGenLow - rxDrive set to %i, attenuation set to %i, cal is %i\n", sgRXDrive, attenuation, sigGenSetting.Calibration); + + #ifdef USE_WIFI + if ( numberOfWebsocketClients > 0 ) + pushSigGenSettings (); + #endif + + changedSetting = false; + } + // Get current touch state and coordinates boolean pressed = tft.getTouch(&t_x, &t_y); // Just uses standard TFT_eSPI function as not bothered about speed @@ -154,6 +186,7 @@ void doSigGenLow () case 5: case 6: incrementFreq( pow(10, 8-b) ); + changedSetting=true; break; case 7: // Decrement buttons @@ -164,6 +197,7 @@ void doSigGenLow () case 12: case 13: decrementFreq( pow(10, 15-b) ); + changedSetting=true; break; case 14: // Return to SAlo mode @@ -172,21 +206,6 @@ void doSigGenLow () case 15: // toggle the output on/off sigGenOutputOn = !sigGenOutputOn; - if (sigGenOutputOn) { - SetRX(3); // both LO and RX in transmit. Output levels have been set in the init function - key[b].drawButton(true, sig_keys[b].activeText); - tft.setCursor(sig_keys[b].x + 30, sig_keys[b].y); - tft.fillRect(sig_keys[b].x + 30, sig_keys[b].y, sig_keys[b].x + 60, sig_keys[b].y + 10, SIG_BACKGROUND_COLOR); - tft.setTextColor(TFT_GREEN, SIG_BACKGROUND_COLOR ); - tft.print(" ON"); - } else { - SetRX(1); // Both in receive - key[b].drawButton(false, sig_keys[b].text); - tft.setCursor(sig_keys[b].x + 30, sig_keys[b].y); - tft.fillRect(sig_keys[b].x + 30, sig_keys[b].y, sig_keys[b].x + 60, sig_keys[b].y + 10, SIG_BACKGROUND_COLOR); - tft.setTextColor(TFT_WHITE, SIG_BACKGROUND_COLOR ); - tft.print("OFF"); - } break; case 16: // launch menu @@ -224,6 +243,33 @@ void doSigGenLow () return; } } + + // check if state changed - can change from command or from wifi + switch (b) { + case 15: // On/Off button + if (oldSigGenOutputOn != sigGenOutputOn) + { + if (sigGenOutputOn) { + SetRX(3); // both LO and RX in transmit. Output levels have been set in the init function + key[b].drawButton(true, sig_keys[b].activeText); + tft.setCursor(sig_keys[b].x + 30, sig_keys[b].y); + tft.fillRect(sig_keys[b].x + 30, sig_keys[b].y, sig_keys[b].x + 60, sig_keys[b].y + 10, SIG_BACKGROUND_COLOR); + tft.setTextColor(TFT_GREEN, SIG_BACKGROUND_COLOR ); + tft.print(" ON"); + } else { + SetRX(1); // Both in receive + key[b].drawButton(false, sig_keys[b].text); + tft.setCursor(sig_keys[b].x + 30, sig_keys[b].y); + tft.fillRect(sig_keys[b].x + 30, sig_keys[b].y, sig_keys[b].x + 60, sig_keys[b].y + 10, SIG_BACKGROUND_COLOR); + tft.setTextColor(TFT_WHITE, SIG_BACKGROUND_COLOR ); + tft.print("OFF"); + } + changedSetting = true; + } + break; + + } // on of state change switch + } // end of keys loop @@ -232,12 +278,15 @@ void doSigGenLow () // Check if slider touched if ( sliderPressed( pressed, t_x, t_y) ) { - float p = sliderPercent( t_x ); // position of slider in % - float pwr = p * (ATTENUATOR_RANGE)/100.0 + sigGenSetting.Calibration - ATTENUATOR_RANGE; + p = sliderPercent( t_x ); // position of slider in % + float pwr = p * (sliderRange)/100.0 + sigGenSetting.Calibration - sliderRange; drawSlider ( SLIDER_X, SLIDER_Y, p, pwr, "dBm" ); - att.SetAtten ( ( 100.0 - p ) / 100.0 * ATTENUATOR_RANGE ); // set attenuator to give required output sigGenSetting.Power = pwr; + changedSetting = true; + } else { + p = ( sigGenSetting.Power - (sigGenSetting.Calibration - sliderRange) ) * 100.0 / sliderRange; + drawSlider ( SLIDER_X, SLIDER_Y, p, sigGenSetting.Power, "dBm" ); } @@ -266,12 +315,15 @@ void doSigGenLow () if (sigGenOutputOn) { delayMicroseconds(300); - SetRX(3); + SetRX(3); // both LO and RX in tx mode } + changedSetting = true; } oldFreq = sigGenSetting.Frequency; oldIF = setting.IF_Freq; + oldSigGenOutputOn = sigGenOutputOn; + } diff --git a/SweepLo.ino b/SweepLo.ino index 722a72e..b319a19 100644 --- a/SweepLo.ino +++ b/SweepLo.ino @@ -73,6 +73,7 @@ static bool resetAverage; // Flag to indicate a setting has changed and avera static bool jsonDocInitialised = false; static uint16_t chunkIndex; static uint32_t offsetIF; // IF frequency offset by half the bandwidth to position in the centre of the filter +static uint32_t tgIF; // Track gen IF - SA IF plus any offset if both SI4432 defined @@ -181,10 +182,20 @@ static uint32_t offsetIF; // IF frequency offset by half the bandwidth to pos tg_lo.RxMode(); #endif +#if defined(SI_TG_IF_CS) && defined(SI_TG_LO_CS) + if (tgLO_OK && tgIF_OK && (trackGenSetting.Mode == 2) ) // tracking gen as signal generator + { + tg_if.SetFrequency ( setting.IF_Freq + trackGenSetting.Offset ); + tg_lo.SetFrequency ( setting.IF_Freq + trackGenSetting.Offset + trackGenSetting.Frequency ); + tg_lo.TxMode ( trackGenSetting.LO_Drive ); // Set tracking generator LO on + tg_if.TxMode ( trackGenSetting.IF_Drive ); // Set tracking generator IF on + } +#endif } // initSweep || changedSetting autoSweepStep = 0; // Set the step counter to zero + sweepStep = 0; autoSweepFreq = setting.ScanStart; // Set the start frequency. nextPointFreq = autoSweepFreq + autoSweepFreqStep; @@ -207,6 +218,12 @@ static uint32_t offsetIF; // IF frequency offset by half the bandwidth to pos tempIF = offsetIF; } + // track gen IF follows LO if only one SI4432, otherwise its offset by an amount to reduce blow by + if (tgLO_OK) + tgIF = tempIF + trackGenSetting.Offset; + else + tgIF = tempIF; + spurToggle = !spurToggle; @@ -225,7 +242,7 @@ static uint32_t offsetIF; // IF frequency offset by half the bandwidth to pos #ifdef SI_TG_IF_CS if (tgIF_OK && (trackGenSetting.Mode == 1) ) - tg_if.SetFrequency ( tempIF + trackGenSetting.Offset ); // Set tracking generator IF for the sweep + tg_if.SetFrequency ( tgIF ); // Set tracking generator IF for the sweep #endif } @@ -233,13 +250,11 @@ static uint32_t offsetIF; // IF frequency offset by half the bandwidth to pos #ifdef SI_TG_LO_CS if (tgLO_OK && (trackGenSetting.Mode == 1) ) - tg_lo.SetFrequency ( tempIF + autoSweepFreq + trackGenSetting.Offset ); // Set tracking generator LO + tg_lo.SetFrequency ( tgIF + autoSweepFreq ); // Set tracking generator LO #endif setFreqMicros = micros(); // Store the time the frequency was changed -// if (trackGenSetting.Mode == 1) // debug -// Serial.printf("tglo start %i at %i\n", tg_lo.GetFrequency(), setFreqMicros); /* * Actual frequency in the SI4432 is rounded and is limited by the possible resolution @@ -253,22 +268,15 @@ static uint32_t offsetIF; // IF frequency offset by half the bandwidth to pos { jsonDocument.clear (); chunkIndex = 0; - - jsonDocument["PreAmp"] = setting.PreampGain; // Fixed gain - jsonDocument["mType"] = "chunkSweep"; - jsonDocument["StartIndex"] = 0; - jsonDocument["sweepPoints"] = sweepPoints; - jsonDocument["sweepTime"] = (uint32_t)(sweepMicros/1000); + initChunkSweepDoc (sweepStep); Points = jsonDocument.createNestedArray ( "Points" ); // Add Points array jsonDocInitialised = true; } - else jsonDocInitialised = false; #endif // #ifdef USE_WIFI - sweepStep = 0; startFreq = setting.ScanStart + tempIF; // Start freq for the LO stopFreq = setting.ScanStop + tempIF; // Stop freq for the LO @@ -438,7 +446,11 @@ static uint32_t offsetIF; // IF frequency offset by half the bandwidth to pos { Serial.println("webSocketTimeout"); Serial.println(wsBuffer); - numberOfWebsocketClients = 0; + websocketFailCount++; + if (websocketFailCount > 2) + numberOfWebsocketClients = 0; + } else { + websocketFailCount = 0; // reset if OK } // Serial.print("j"); } @@ -450,12 +462,8 @@ static uint32_t offsetIF; // IF frequency offset by half the bandwidth to pos if ( ( chunkIndex >= wiFiPoints ) || !jsonDocInitialised ) // Start new jSon document { chunkIndex = 0; - jsonDocument.clear(); - jsonDocument["mType"] = "chunkSweep"; - jsonDocument["StartIndex"] = sweepStep; - jsonDocument["sweepPoints"] = sweepPoints; - jsonDocument["sweepTime"] = (uint32_t)(sweepMicros/1000); - Points = jsonDocument.createNestedArray ("Points" ); // Add Points array + initChunkSweepDoc (sweepStep); + Points = jsonDocument.createNestedArray ( "Points" ); // Add Points array jsonDocInitialised = true; } } diff --git a/cmd.cpp b/cmd.cpp index 291f414..c652e60 100644 --- a/cmd.cpp +++ b/cmd.cpp @@ -106,6 +106,7 @@ extern uint32_t colourTest; extern Marker marker[MARKER_COUNT]; // Array of marker objects +extern uint16_t sigGenOutputOn; // signal generator state - 0 = off, 1 = on /* * Functions still in the main program file. Maybe some need to move here? @@ -183,6 +184,13 @@ extern uint8_t dBmToRSSI ( double dBm ); { "RXSWEEP", MSG_RX_SWEEP }, // Set RX Sweep Mode { "RXSIGNAL", MSG_RXSIGNAL }, // IF sweep signal frequency { "EXTGAIN", MSG_EXTGAIN }, // External gain or attenuation + { "SGON", MSG_SGON }, // turn on signal generator output + { "SGOFF", MSG_SGOFF }, // turn off signal generator output + { "SGFREQ", MSG_SGFREQ }, // Set Signal Generator Frequency + { "TRACKON", MSG_TGON }, // turn on tracking generator output + { "TRACKOFF", MSG_TGOFF }, // turn off tracking generator output + { "TRACKSIG", MSG_TGSIG }, // turn off tracking generator output + { "TGFREQ", MSG_TGFREQ }, // Set Track gen freq for sig gen mode { "", MSG_NONE } // Unrecognized command }; @@ -196,7 +204,7 @@ int msgCount = ELEMENTS ( msgTable); void ShowMenu () { - Serial.printf ( "\nTiny Spectrum Analyzer Version %s - User Commands:\n\n", PROGRAM_VERSION ); + Serial.printf ( "\nsimpleSA Spectrum Analyzer %s - User Commands:\n\n", PROGRAM_VERSION ); Serial.println ( "Sweep Settings:\n" ); Serial.print ( " START.........Sweep start frequency, currently: " ); @@ -248,25 +256,53 @@ void ShowMenu () Serial.printf ( " WFMIN.........Set the minimum RSSI level for waterfall colouring: %i\n", setting.WaterfallMin ); Serial.printf ( " WFGAIN........Set the gain for waterfall colouring: %d\n", setting.WaterfallGain ); - Serial.println ( "\nOther Commands:\n" ); - Serial.print ( " DRIVE.........Local oscillator drive level [0 to 7]; currently: " ); - Serial.println ( setting.Drive ); + Serial.println ( "\nSignal Generator Commands:\n" ); + + Serial.println ( " SGON..........Turn on signal generator output" ); + Serial.print ( " SGOFF.........Turn off signal generator output; currently " ); + Serial.println ( sigGenOutputOn ); + + Serial.print ( " SGFREQ........Signal Generator frequency, currently: " ); + Serial.println ( FormatFrequency ( sigGenSetting.Frequency )); Serial.print ( " SGLODRIVE.....Local oscillator drive level in signal generator mode [0 to 7]; currently: " ); Serial.println ( sigGenSetting.LO_Drive ); - Serial.print ( " SGRXDRIVE.....Local oscillator drive level in signal generator mode [0 to 7]; currently: " ); + Serial.print ( " SGRXDRIVE.....RX SI4432 oscillator drive level in signal generator mode [0 to "); + Serial.print ( RX_SI4432_MAX_DRIVE ); + Serial.print ( "]; currently: " ); Serial.println ( sigGenSetting.RX_Drive ); +#ifdef SI_TG_IF_CS + Serial.println ( "\nTracking Generator Commands:\n" ); + + Serial.println ( " TRACKON.......Turn on tracking generator output" ); +#ifdef SI_TG_LO_CS + Serial.println ( " TRACKSIG......Turn on tracking generator signal generator output" ); +#endif + Serial.print ( " TRACKOFF......Turn off tracking generator output; currently " ); + Serial.println ( trackGenSetting.Mode ); + +#ifdef SI_TG_LO_CS Serial.print ( " TGLODRIVE.....Local oscillator drive level in tracking generator mode [0 to 7]; currently: " ); Serial.println ( trackGenSetting.LO_Drive ); - +#endif Serial.print ( " TGIFDRIVE.....Local oscillator drive level in tracking generator mode [0 to 7]; currently: " ); Serial.println ( trackGenSetting.IF_Drive ); - +#ifdef SI_TG_LO_CS Serial.print ( " TGOFFSET......Tracking generator offset from SA IF; currently: " ); Serial.println ( trackGenSetting.Offset ); + Serial.print ( " TGFREQ........Tracking generator signal generator frequency; currently: " ); + Serial.println ( trackGenSetting.Frequency ); +#endif +#endif + + + Serial.println ( "\nOther Commands:\n" ); + + Serial.print ( " DRIVE.........Local oscillator drive level [0 to 7]; currently: " ); + Serial.println ( setting.Drive ); Serial.println ( " SAVE .........Save the current scan configuration [0 to 4]" ); @@ -759,6 +795,29 @@ uint8_t reg69; // Ditto return true; +/* + * Signal Generator On/Off commands + * + */ + case MSG_SGON: + SetSGState(1); + return true; + + case MSG_SGOFF: + SetSGState(0); + return true; + + case MSG_SGFREQ: + if ( dataLen != 0 ) // Frequency specified? + { + freq1 = ParseFrequency ( dataBuff ); // Yes, get new frequency + SetSGFreq (freq1); + } + Serial.printf ( "Signal Generator frequency: %i\n", FormatFrequency ( freq1 )); + return true; + + + /* * The "SGLODRIVE" command sets the local oscillator "drive" level in signal generator mode. @@ -769,7 +828,7 @@ uint8_t reg69; // Ditto tempValue = atoi ( dataBuff ); // Yes, convert to a number if (( tempValue < MIN_DRIVE ) || ( tempValue > MAX_DRIVE )) - Serial.printf ( "Invalid drive specification: %d\n", tempValue ); + Serial.printf ( "Invalid LO drive: %d\n", tempValue ); else // Set the transmitter drive level SetSGLoDrive ( tempValue ); // "SetSGLoDrive" saves the settings } @@ -781,17 +840,17 @@ uint8_t reg69; // Ditto return true; /* - * The "SGLODRIVE" command sets the receiver (IF) oscillator "drive" level in signal generator mode. + * The "SGRXDRIVE" command sets the receiver (IF) oscillator "drive" level in signal generator mode. */ case MSG_SG_RX_DRIVE: if ( dataLen != 0 ) // Drive level specified? { tempValue = atoi ( dataBuff ); // Yes, convert to a number - if (( tempValue < MIN_DRIVE ) || ( tempValue > MAX_DRIVE )) - Serial.printf ( "Invalid drive specification: %d\n", tempValue ); + if (( tempValue < MIN_DRIVE ) || ( tempValue > RX_SI4432_MAX_DRIVE )) + Serial.printf ( "Invalid RX drive: %d - (%d-%d)\n", tempValue, MIN_DRIVE, RX_SI4432_MAX_DRIVE ); else // Set the transmitter drive level - SetSGRxDrive ( tempValue ); // "SetTGRxDrive" saves the settings + SetSGRxDrive ( tempValue ); // "SetSGRxDrive" saves the settings } Serial.printf ( "SigGen RX Drive: %d (+%udBm)\n", sigGenSetting.RX_Drive, driveLevel[sigGenSetting.RX_Drive] ); @@ -800,8 +859,26 @@ uint8_t reg69; // Ditto return true; +/* + * Tracking Generator On/Off commands + * + */ + case MSG_TGON: + SetTracking(1); + return true; + + case MSG_TGOFF: + SetTracking(0); + return true; + #ifdef SI_TG_LO_CS + + case MSG_TGSIG: + SetTracking(2); + return true; + + /* * The "TGLODRIVE" command sets the local oscillator "drive" level in tracking generator mode. * (only valid if two SI4432 used for the tracking generator) @@ -1578,6 +1655,14 @@ uint8_t reg69; // Ditto Serial.printf ( "Tracking Generator IF offset: %i\n", trackGenSetting.Offset ); // sort out signed version of format frequency!!!!!!!!!!!!!!!!!!! return true; + case MSG_TGFREQ: + if ( dataLen != 0 ) // Frequency specified? + { + freq1 = ParseFrequency ( dataBuff ); // Yes, get new frequency + SetTGFreq (freq1); + } + Serial.printf ( "Tracking Signal Generator frequency: %i\n", FormatFrequency ( trackGenSetting.Frequency )); + return true; /* @@ -2295,6 +2380,7 @@ void RequestSetPowerLevel ( float o ) /* * "SetPowerLevel" + * Adjusts displayed power to match the actual input signal power - calibration function */ void SetPowerLevel ( double o ) @@ -2433,6 +2519,32 @@ int oldLevel = setting.Drive; } +/* Set SGFreq sets the signal generator Frequency + * Signal generator frequency may change frequently, so don't save the setting + * Settings are saved when leaving the mode + * parameter is in Hz + */ +bool SetSGFreq (uint32_t f) +{ + if ( ( f >= MIN_SIGLO_FREQ ) && ( f <= MAX_SIGLO_FREQ ) ) + { + sigGenSetting.Frequency = f; + return true; + } + else + return false; +} + + +/* + * Sig gen state is not saved - always want to start in off state + */ + +void SetSGState (uint16_t s) +{ + sigGenOutputOn = s; +} + /* * "SetSGLoDrive" sets the transmitter max output level in signal generator mode. * @@ -2479,13 +2591,16 @@ int oldLevel = sigGenSetting.LO_Drive; * 1 => +2dBm 5 => +14dBm * 2 => +5dBm 6 => +17dBm * 3 => +8dBm 7 => +20dBm + * Note the power limits of the B3555 SAW filter is 10dBm + * RX_SI4432_MAX_DRIVE is set in my_SA.h to suit the attenuator pad and losses + * in your build. */ void SetSGRxDrive ( uint8_t level ) { int oldLevel = sigGenSetting.RX_Drive; - if (( level < 0 ) || ( level > 7 )) + if (( level < 0 ) || ( level > RX_SI4432_MAX_DRIVE )) return; else @@ -2503,6 +2618,20 @@ int oldLevel = sigGenSetting.RX_Drive; } +void SetSGPower ( int16_t dBm ) +{ + // Add algorithm to set attenuator and IF drive level + // initially limit to just set attenuator + + if ( dBm > sigGenSetting.Calibration ) + dBm = sigGenSetting.Calibration; + if ( dBm < (sigGenSetting.Calibration - ATTENUATOR_RANGE - RX_SI4432_MAX_DRIVE * 3) ) + dBm = sigGenSetting.Calibration - ATTENUATOR_RANGE; + + sigGenSetting.Power = dBm; + changedSetting = true; +} + #ifdef SI_TG_LO_CS /* * "SetTGLoDrive" sets the transmitter max output level for the tracking generator. @@ -2618,6 +2747,28 @@ int32_t GetTGOffset ( ) return trackGenSetting.Offset; } +/* + * Set the Track Gen frequency - M0WID addition + */ + +bool SetTGFreq ( int32_t freq ) +{ +int32_t oldFreq = trackGenSetting.Frequency; + + if (( freq < MIN_SIGLO_FREQ ) || ( freq > MAX_SIGLO_FREQ )) // If out of limits + return false; // Don't change it + + trackGenSetting.Frequency = freq; + + if ( oldFreq != trackGenSetting.Frequency ) + { + changedSetting = true; + WriteTrackGenSettings (); + } + + return true; // Frequency was good +} + /* * "SetSweepStart" and "GetSweepStart" were added in Version 2.3. They used to be in diff --git a/cmd.h b/cmd.h index b09f970..7ee44f3 100644 --- a/cmd.h +++ b/cmd.h @@ -78,6 +78,13 @@ #define MSG_RX_SWEEP 49 // Set the RX Sweep Mode #define MSG_RXSIGNAL 50 // Set frequency of injected signal for IF Sweep #define MSG_EXTGAIN 51 // Set external gain or attenuation +#define MSG_SGON 52 // Turn Signal Generator output on +#define MSG_SGOFF 53 // Turn Signal Generator output off +#define MSG_SGFREQ 54 // Set Signal Generator Frequency +#define MSG_TGON 55 // Turn Tracking Generator output on +#define MSG_TGOFF 56 // Turn Tracking Generator output off +#define MSG_TGFREQ 57 // Set Track Gen frequency for sig gen mode +#define MSG_TGSIG 58 // Set Track Gen sig gen mode #define MSG_COLOURTEST 99 // test of waterfall colours - remove this when done! @@ -139,13 +146,17 @@ void SetGenerate ( int8_t g ); // Puts the unit into or out of signal generat bool SetIFFrequency ( int32_t f ); // Sets the IF frequency void SetLoDrive ( uint8_t level ); // Sets LO Si4432 output level +void SetSGState (uint16_t s); +bool SetSGFreq ( uint32_t freq); // set signal generator frequency - returns false if invalid void SetSGLoDrive ( uint8_t level ); void SetSGRxDrive ( uint8_t level ); +void SetSGPower ( int16_t dBm ); // Set signal generator attenuator and drive levels void SetTracking ( int8_t m ); // set tracking generator mode void SetTGLoDrive ( uint8_t level ); // set tracking generator drive void SetTGIfDrive ( uint8_t level ); bool SetTGOffset ( int32_t offset); // set tracking generator offset - returns false if invalid +bool SetTGFreq ( int32_t freq); // set tracking generator freq for sig gen mode - returns false if invalid int32_t GetTGOffset (void ); void SetTGPower ( int16_t dBm ); // Set TG attenuator and drive levels diff --git a/data/about.html b/data/about.html index 64bbb17..9b87ab5 100644 --- a/data/about.html +++ b/data/about.html @@ -1,7 +1,7 @@  - [TinySA] + [simpleSA] @@ -46,18 +46,18 @@

About

- The TinySA has been developed by Erik PD0EK. - This version has been adapted to run on the ESP32 DevKit module by Dave M0WID and John WA2FZW. + This simpleSA running on an ESP32 has been adapted by Dave M0WID and John WA2FZW.
+ It was based on an early prototype design of the TinySA by Erik PD0EK.
Information can be found at https://groups.io/g/HBTE


-
- To reboot click -
+
+ To reboot click +
- + diff --git a/data/index.html b/data/index.html index 9bc51c1..e3498d6 100644 --- a/data/index.html +++ b/data/index.html @@ -32,7 +32,7 @@ -TinySA-ESP +simpleSA @@ -41,7 +41,7 @@ -
+
+
+ +
+ +
+
Signal Generator
+
+
+ +
+ + + + + , + + + + , + + + + Hz   + +
+ + + +
+

+ + + dBm +

+
+ +
+ +
+
-

Sweep

+
+ + +
@@ -113,9 +167,10 @@
- + + dB - + dB
@@ -137,25 +192,36 @@
- +
- - - dBm + +
+ + + dBm
+
+ + + MHz +
+

- - - - + + pts + ms
@@ -179,7 +245,7 @@ dB
- + dBm
@@ -257,8 +323,9 @@
Pings:
-
Refresh Interval: +
Refresh: + ms
@@ -268,8 +335,17 @@
+ + + + + +
+ + + + +
+
+
+
+ +
+ +
+ + +
+
+ + + MHz +
+
+
+ + + dBm +
+
+

Settings

+
+ + + dB +
+
+ + + dBm +
+
+
+ + + dBm +
+
+ + + MHz +
+ +
+ +
+ + + + + +
+
+
+
+
+
Host: + + + +
+
Status: + +
+
Pings: + +
+
Refresh Interval: + +
+
+
+ + +
+
+ + + + diff --git a/data/styles.css b/data/styles.css index a6ce8f6..0a30fd8 100644 --- a/data/styles.css +++ b/data/styles.css @@ -22,7 +22,7 @@ } .norm { - width: 100%; + width: 95%; height: 3vh; font-family: Arial, Helvetica, sans-serif; margin-top: 5px; @@ -127,6 +127,14 @@ input[type="number"] { background-color: lightgrey; } +.sweep-display { + border: 0; + text-align: right; + width: 65px; + display: inline-block; + background-color: lightgrey; +} + .message-display { border: 0; text-align: left; @@ -156,17 +164,47 @@ input[type="number"] { border: solid 1px grey; text-align: right; text-align-last: right; - width: 75px; + width: 77px; display: inline-block; } + +.Sweep-select { + border: solid 1px grey; + text-align: left; + text-align-last: left; + width: 150px; + display: inline-block; + color: black; + font-weight: bolder; + background-repeat: no-repeat; + margin: 10px; + } .select-option { text-align: right; text-align-last: right; } +.sweep-option { + text-align: left; + text-align-last: left; +} -.set-button { - font-size: 14px; +.inc-button { + width: 60px; + height: 30px; + font-size: 14px; + float: right; + margin-right:60px; + margin-top:3px; +} + +.on-button { + width: 60px; + height: 33px; + font-size: 14px; + float: right; + margin-right:0px; + margin-top:3px; } .setting { @@ -176,8 +214,120 @@ input[type="number"] { .setting-label { width: 80px; display: inline-block; + } + +.setting-widelabel { + width: 138px; + display: inline-block; + } + +.sigTitle { + font-size: 36px; + font-weight: bold; } + +.sigFreq { + font-weight: bolder; + font-size: 32px; + margin: 0; + padding: 0; + letter-spacing: -10px; + width: 500px; +} + +.sigFreqLabel { + width: 180px; + display: inline-block; + font-size: 32px; + margin: 0; + padding: 0; + letter-spacing: normal; +} + +.sigFreqText { + display: inline-block; + font-size: 32px; + margin: 0; + padding: 0; + letter-spacing: normal; +} + +input.sigFreqInput { + border: solid 1px grey; + text-align: right; + width: 18px; + display: inline-block; + font-size: 32px; + margin: 0; + padding: 0; +} + +input.sigFrequencyInput { + border: solid 1px grey; + text-align: right; + width: 180px; + display: inline-block; + font-size: 32px; + margin: 0; + padding: 0; +} + +input.sigFreqInput::-webkit-outer-spin-button, +input.sigFreqInput::-webkit-inner-spin-button { + -webkit-appearance: none; + margin: 0; +} +input.sigFreqInput { + -moz-appearance: textfield; +} + +.sigLevelLabel { + width: 180px; + display: inline-block; + font-size: 32px; + letter-spacing: normal; + } + +input.sigLevelInput { + border: solid 1px grey; + text-align: right; + width: 180px; + display: inline-block; + font-size: 32px; + } + + TH, .bold { background-color: lightblue; color: black; } + +.slider { + -webkit-appearance: none; + width: 340px; + height: 15px; + border-radius: 5px; + background: #d3d3d3; + outline: none; + opacity: 0.7; + -webkit-transition: .2s; + transition: opacity .2s; +} + +.slider::-webkit-slider-thumb { + -webkit-appearance: none; + appearance: none; + width: 25px; + height: 25px; + border-radius: 50%; + background: #4CAF50; + cursor: pointer; +} + +.slider::-moz-range-thumb { + width: 25px; + height: 25px; + border-radius: 50%; + background: #4CAF50; + cursor: pointer; +} diff --git a/my_SA.h b/my_SA.h index d5d28f2..5ba9dd4 100644 --- a/my_SA.h +++ b/my_SA.h @@ -25,6 +25,7 @@ #define USE_WIFI true // Changed in Version 2.6 to true/false // #define USE_ACCESS_POINT // Comment out if want to connect to SSID, leave in to use access point +// #define AP_PASSWORD "none" #define WIFI_SSID ":)" // SSID of your WiFi if not using access point #define WIFI_PASSWORD "S0ftR0ckRXTX" // Password for your WiFi @@ -64,6 +65,9 @@ // #define SLIDER_MAX_POWER -13.0 #define ATTENUATOR_RANGE 30 // in dB +// the B3555 SAW filter has max power rating of 10dBm. +// Drive of 4 = 11dBm but 1 dB pad in my build. If you have a larger attenuator pad you can try higher powers + #define RX_SI4432_MAX_DRIVE 4 // corresponds to 11dBm /* * These definitions control the values that get set when you select "AUTO SETTINGS" from diff --git a/si4432.cpp b/si4432.cpp index abeaf62..82e9c77 100644 --- a/si4432.cpp +++ b/si4432.cpp @@ -272,7 +272,7 @@ const char* unit[4] = { "RX", "TX", "TGIF", "TGLO" }; // For debugging WriteByte ( REG_OFC1, SW_RESET ); // Always perform a system reset - while ( millis() - startTime < 10000 ) // Try for 10 seconds + while ( millis() - startTime < 2000 ) // Try for 2 seconds { regRead = ReadByte ( REG_IS2 ); diff --git a/simpleSA.h b/simpleSA.h index 826ff26..244df2b 100644 --- a/simpleSA.h +++ b/simpleSA.h @@ -32,7 +32,7 @@ #define PROGRAM_NAME "simpleSA" // These are for the WiFi interface -#define PROGRAM_VERSION "0.01" // Current version is 0.01 - beta! +#define PROGRAM_VERSION "Version 0.1" // Current version - beta! /* @@ -186,7 +186,7 @@ */ enum { SA_LOW_RANGE, SA_HIGH_RANGE, SIG_GEN_LOW_RANGE, SIG_GEN_HIGH_RANGE, - IF_SWEEP, ZERO_SPAN_LOW_RANGE, ZERO_SPAN_HIGH_RANGE, TRACKING_GENERATOR, BANDSCOPE, RX_SWEEP }; + IF_SWEEP, ZERO_SPAN_LOW_RANGE, ZERO_SPAN_HIGH_RANGE, BANDSCOPE, RX_SWEEP }; /* diff --git a/simpleSA.ino b/simpleSA.ino index 228c229..9c3a010 100644 --- a/simpleSA.ino +++ b/simpleSA.ino @@ -127,11 +127,20 @@ * Additional functions in ui.cmd to allow signed frequency entry. * * Version 3.0f Changes by M0WID + * + * Version 0.03 * renamed simpleSA. Doesn't seem that simple to me! * First go at bandscope mode * VSPI reduced to 10Mhz as some boards will not run at 16MHz * Put onto github - lets see how it works! Version numbering changed - still in beta! * + * Version 0.1 + * Tracking generator now can be used as a signal generator + * Web page for signal generator + * RX sweep for testing the SI4432 FIR filters + * Output range of signal generator increased by also reducing SI4432 output power as well as uing attenuator + * Storage feature - temporary only not to disk - added to web page traces + * X grid lines added to web chart */ @@ -348,13 +357,14 @@ uint8_t numberOfWebsocketClients; // How many connections uint16_t wiFiPoints; // Push data to the wifi clinets when this many points collected unsigned long wiFiTargetTime = WIFI_UPDATE_TARGET_TIME; unsigned long websocketInterval = WEBSOCKET_INTERVAL; +uint16_t websocketFailCount; #ifdef USE_WIFI // Json document buffers -size_t capacity = JSON_ARRAY_SIZE ( MAX_WIFI_POINTS + 1 ) - + ( MAX_WIFI_POINTS + 1 ) * JSON_OBJECT_SIZE ( 2 ) + JSON_OBJECT_SIZE( 5 ); +//size_t capacity = JSON_ARRAY_SIZE ( MAX_WIFI_POINTS + 1 ) +// + ( MAX_WIFI_POINTS + 1 ) * JSON_OBJECT_SIZE ( 2 ) + JSON_OBJECT_SIZE( 5 ); -static DynamicJsonDocument jsonDocument ( capacity ); // Buffer for json data to be pushed to the web clients +static DynamicJsonDocument jsonDocument ( 4000 ); // Buffer for json data to be pushed to the web clients static JsonArray Points = jsonDocument.createNestedArray ( "Points" ); // add Points array #endif @@ -380,7 +390,7 @@ int16_t minGrid; * Some varibales for the various operating modes */ uint16_t tinySA_mode = SA_LOW_RANGE; // Low frequency range -const char *modeText[] = { "SALo", "SAHi", "SGLo", "SGHi", "IFSw", "0SpL", "0SpH", "TrGn", "BScp", "RXSw" }; // For mode display +const char *modeText[] = { "SALo", "SAHi", "SGLo", "SGHi", "IFSw", "0SpL", "0SpH", "BScp", "RXSw" }; // For mode display float bandwidth; // The current bandwidth (not * 10) @@ -503,7 +513,7 @@ uint16_t spacing = 10000; bool paused = false; -bool sigGenOutputOn = false; +uint16_t sigGenOutputOn = false; uint32_t oldFreq; // to store the current Signal Generator frequency /* @@ -671,6 +681,7 @@ bool fsStatus = false; // True if SPIFFS loads ok // If the tracking generator IF SI4432 is defined, then check to see if it is connected tgIF_OK = false; + #ifdef SI_TG_IF_CS // pinMode (SI_TG_IF_CS, INPUT); //Start off in input mode, no pullup // delay(2); @@ -680,6 +691,8 @@ bool fsStatus = false; // True if SPIFFS loads ok // delay(2); // tgIF_OK = tg_if.Init ( config.tgIF_capacitance ); + tft.setCursor(0,180); + tft.println ( "Initializing track gen IF SI4432" ); if ( tg_if.Init ( config.tgIF_capacitance ) ) { tft.println ("Tracking IF initialised"); @@ -708,6 +721,7 @@ bool fsStatus = false; // True if SPIFFS loads ok // If the tracking generator LO SI4432 is defined, then check to see if it is connected tgLO_OK = false; + #ifdef SI_TG_LO_CS // pinMode (SI_TG_LO_CS, INPUT); //Start off in input mode, no pullup // delay(2); @@ -715,6 +729,9 @@ bool fsStatus = false; // True if SPIFFS loads ok // // Tracking gen LO present - initialise it, but not in TX mode yet // pinMode (SI_TG_LO_CS, OUTPUT); // delay(2); + + tft.println ( "Initializing track gen LO SI4432" ); + tgLO_OK = tg_lo.Init ( config.tgLO_capacitance ); if ( tgLO_OK ) tft.println ("Tracking LO initialised"); @@ -729,7 +746,9 @@ bool fsStatus = false; // True if SPIFFS loads ok // pinMode (SI_TG_LO_CS, OUTPUT); // digitalWrite(SI_TG_LO_CS, HIGH); // make sure it doesn't get selected // } - +#else + pinMode (25, OUTPUT); + digitalWrite(25, HIGH); // make sure it doesn't get selected #endif @@ -809,7 +828,7 @@ bool fsStatus = false; // True if SPIFFS loads ok // tft.println("Setup Complete"); - Serial.printf ( "\nTinySA Version %s Initialization Complete\n", PROGRAM_VERSION ); + Serial.printf ( "\nsimpleSA %s Initialization Complete\n", PROGRAM_VERSION ); ShowMenu (); // Display the menu of commands on serial monitor @@ -1113,6 +1132,21 @@ void init_sweep() } +/* + * Initialise the JSON document that is used to push the sweep data to the web clients + * Used in all the sweep modes + */ +void initChunkSweepDoc (uint32_t startIndex) +{ + jsonDocument.clear (); + jsonDocument["PreAmp"] = setting.PreampGain; // Fixed gain + jsonDocument["mType"] = "chunkSweep"; + jsonDocument["StartIndex"] = startIndex; + jsonDocument["sweepPoints"] = sweepPoints; + jsonDocument["sweepTime"] = (uint32_t)(sweepMicros/1000); +} + + /* * Initialise high frequency mode sweep. diff --git a/simpleSA_wifi.cpp b/simpleSA_wifi.cpp index 812d9ae..6a5b713 100644 --- a/simpleSA_wifi.cpp +++ b/simpleSA_wifi.cpp @@ -33,12 +33,15 @@ extern uint16_t displayPoints; extern uint16_t xDelta; extern uint16_t waterfallHeight; +extern unsigned long sweepMicros; // To report the scan time + extern int bpfCount; // Number of elements in the bandpassFilters array extern int updateSidebar; // Flag to indicate no of clients has changed extern void ClearDisplay (); extern void DisplayError ( uint8_t severity, const char *l1, const char *l2, const char *l3, const char *l4 ); +extern void setMode (uint16_t newMode); /* * In Version 1.8, the transmitter and receiver Si4432 modules are implemented as @@ -54,6 +57,7 @@ extern uint8_t AGC_Reg; // Fixed value for preampGain if not auto extern uint32_t startFreq_IF; extern uint32_t stopFreq_IF; extern uint32_t sigFreq_IF; +extern uint16_t sigGenOutputOn; extern uint32_t startFreq_RX; extern uint32_t stopFreq_RX; @@ -101,7 +105,14 @@ boolean startAP () // Start the WiFi Access Point, keep the user informed. { ClearDisplay (); // Fade to black + + Serial.println ( "Starting Access Point" ); // Put in the instructions + + delay(2000); + + // Scan WiFi SSIDs + WiFi.scanNetworks(true); /* @@ -123,9 +134,9 @@ boolean startAP () // Start the WiFi Access Point, keep the user informed. DisplayError ( ERR_WARN, "Failed to open AP:", "WiFi Disabled", NULL, NULL ); else - ipAddress = WiFi.localIP (); + ipAddress = WiFi.softAPIP(); - Serial.printf ( "Access Point started, result = %b \n", result ); + Serial.printf ( "Access Point started, result = %i \n", result ); return result; } @@ -210,10 +221,32 @@ void webSocketEvent ( uint8_t num, WStype_t type, uint8_t* payload, size_t paylo /* - * Format of message to process * - * #a 123.123 Start frequency - * #b 123.123 Stop frequency + * Message format + * #(code) value where code is a single char. Case is important + * + * a start freq (MHz) - sig gen freq if in sig gen mode + * b stop frequency + * c centre frequency + * s Span + * d Local Oscillator Drive + * g PreAmpGain/Mode + * i IF frequency + * m mode + * p set actual power to peak value + * o RefOut + * r request Settings are pushed + * A internal attenuation (PE4302) + * E external gain ( eg attenuator(-ve) or preamp(+ve) ) + * R requested RBW + * S Spur reduction Off/On + * t trackGen Off/On/Generate + * T trackGen output level + * f trackgen signal generator frequency + * F Sig Gen frequency + * L Sig Gen level (dBm) + * G Sig Gen Off/On + * P Sig Gen set max output level (dBm) * * Other formats are ignored */ @@ -234,11 +267,37 @@ void webSocketEvent ( uint8_t num, WStype_t type, uint8_t* payload, size_t paylo switch ( payload[1] ) { case 'a': - SetSweepStart ( value * 1000000.0 ); // Set sweep start frequency + switch (setting.Mode) { + case SA_LOW_RANGE: + SetSweepStart ( value * 1000000.0 ); // Set Low range sweep start frequency + break; + case SIG_GEN_LOW_RANGE: + SetSweepStart ( value * 1000000.0 ); // Set Low range sweep start frequency + break; + case IF_SWEEP: + SetIFsweepStart ( value * 1000000.0 ); // Set IF sweep start frequency + break; + case RX_SWEEP: + SetRXsweepStart ( value * 1000000.0 ); // Set RX sweep start frequency + break; + case BANDSCOPE: + SetBandscopeStart ( value * 1000000.0 ); // Set sweep start frequency + break; + } break; case 'b': - SetSweepStop ( value * 1000000.0 ); // Set sweep stop frequency + switch (setting.Mode) { + case SA_LOW_RANGE: + SetSweepStop ( value * 1000000.0 ); // Set Low range sweep start frequency + break; + case IF_SWEEP: + SetIFsweepStop ( value * 1000000.0 ); // Set IF sweep start frequency + break; + case RX_SWEEP: + SetRXsweepStop ( value * 1000000.0 ); // Set RX sweep start frequency + break; + } break; case 'c': @@ -249,6 +308,10 @@ void webSocketEvent ( uint8_t num, WStype_t type, uint8_t* payload, size_t paylo SetLoDrive ( (uint8_t) value ); break; + case 'f': + SetTGFreq ( value ); + break; + case 'g': SetPreampGain( (int) value ); // Set PreAmp gain register break; @@ -257,6 +320,10 @@ void webSocketEvent ( uint8_t num, WStype_t type, uint8_t* payload, size_t paylo SetIFFrequency ( (int32_t) ( value * 1000000.0 )); break; + case 'm': // Set mode + setMode ( (int16_t) ( value )); + break; + case 'o': // Ref Output (LO GPIO2) SetRefOutput ( (int) value ); break; @@ -265,10 +332,43 @@ void webSocketEvent ( uint8_t num, WStype_t type, uint8_t* payload, size_t paylo RequestSetPowerLevel( value ); break; + case 'r': // request of settings by client + switch (setting.Mode) + { + case (SA_LOW_RANGE): + pushSettings(); + break; + + case (IF_SWEEP): + pushIFSweepSettings(); + break; + + case (RX_SWEEP): + pushRXSweepSettings(); + break; + + case (BANDSCOPE): + pushBandscopeSettings(); + break; + + case (SIG_GEN_LOW_RANGE): + pushSigGenSettings(); + break; + + default: + Serial.println("Invalid mode in Request setting handler - simpleSA_wifi.cpp"); + + } + break; + case 's': // Adjust sweep span SetSweepSpan ( (int32_t) ( value * 1000000.0 )); break; + case 't': // Tracking Generator off/on/generate + SetTracking ( (int8_t)value ); + break; + case 'A': // Internal Attenuation (PE4302) SetAttenuation ( value ); break; @@ -277,6 +377,18 @@ void webSocketEvent ( uint8_t num, WStype_t type, uint8_t* payload, size_t paylo SetExtGain ( value ); break; + case 'F': + SetSGFreq ( value ); // Signal Generator Frequency + break; + + case 'G': + SetSGState ( (uint16_t)value ); // Signal Generator output on/off + break; + + case 'L': // Signal Generator output power (dBm) + SetSGPower ( value ); + break; + case 'R': // Requested RBW. 0=Auto SetRBW ( value ); Serial.printf("Wifi RBW %f\n", value); @@ -286,10 +398,6 @@ void webSocketEvent ( uint8_t num, WStype_t type, uint8_t* payload, size_t paylo SetSpur ( (int8_t)value ); break; - case 't': // Tracking Generator on/off - SetTracking ( (int8_t)value ); - break; - case 'T': // Tracking Generator output power (dBm) SetTGPower ( value ); break; @@ -508,6 +616,7 @@ void onGetSettings (AsyncWebServerRequest *request) JsonObject root = response->getRoot(); root["mType"] = "Settings"; + root["mode"] = setting.Mode; root["dispPoints"] = displayPoints; root["start"] = setting.ScanStart / 1000.0; root["stop"] = setting.ScanStop / 1000.0; @@ -523,6 +632,18 @@ void onGetSettings (AsyncWebServerRequest *request) root["spur"] = setting.Spur; root["tg"] = trackGenSetting.Mode; root["tgPower"] = trackGenSetting.Power; + root["tgFreq"] = trackGenSetting.Frequency; + root["tgMod"] = trackGenSetting.ModulationType; + root["tgModFreq"] = trackGenSetting.ModFrequency; + root["sg"] = sigGenOutputOn; // + root["sgPower"] = sigGenSetting.Power; + root["sgMod"] = sigGenSetting.ModulationType; + root["sgModFreq"] = sigGenSetting.ModFrequency; + root["sgFreq"] = sigGenSetting.Frequency; + root["sgCal"] = sigGenSetting.Calibration; + root["sgRange"] = ATTENUATOR_RANGE + 11; // SI4432 output can be adjusted over 21dBm but max to SAW filter is 10dBm + root["tgCal"] = trackGenSetting.Calibration; + root["tgRange"] = ATTENUATOR_RANGE + 21; // no SAW filter so 20dBm output is possible. if ( AGC_On ) root["PreAmp"] = 0x60; // Auto @@ -546,10 +667,11 @@ if ( numberOfWebsocketClients == 0 ) return; size_t capacity = JSON_ARRAY_SIZE ( SCREEN_WIDTH ) - + SCREEN_WIDTH*JSON_OBJECT_SIZE ( 2 ) + JSON_OBJECT_SIZE ( 16 ); + + SCREEN_WIDTH*JSON_OBJECT_SIZE ( 2 ) + JSON_OBJECT_SIZE ( 17 ); static DynamicJsonDocument jsonDocument ( capacity ); // buffer for json data to be pushed to the web clients jsonDocument["mType"] = "Settings"; + jsonDocument["mode"] = setting.Mode; jsonDocument["dispPoints"] = displayPoints; jsonDocument["start"] = setting.ScanStart / 1000.0; jsonDocument["stop"] = setting.ScanStop / 1000.0; @@ -565,10 +687,21 @@ static DynamicJsonDocument jsonDocument ( capacity ); // buffer for json data to jsonDocument["spur"] = setting.Spur; jsonDocument["tg"] = trackGenSetting.Mode; jsonDocument["tgPower"] = trackGenSetting.Power; - + jsonDocument["tgFreq"] = trackGenSetting.Frequency; + jsonDocument["tgMod"] = trackGenSetting.ModulationType; + jsonDocument["tgModFreq"] = trackGenSetting.ModFrequency; + jsonDocument["sg"] = sigGenOutputOn; // + jsonDocument["sgPower"] = sigGenSetting.Power; + jsonDocument["sgMod"] = sigGenSetting.ModulationType; + jsonDocument["sgModFreq"] = sigGenSetting.ModFrequency; + jsonDocument["sgFreq"] = sigGenSetting.Frequency; + jsonDocument["sgCal"] = sigGenSetting.Calibration; + jsonDocument["sgRange"] = ATTENUATOR_RANGE + 11; // SI4432 output can be adjusted over 21dBm but max to SAW filter is 10dBm + jsonDocument["tgCal"] = trackGenSetting.Calibration; + jsonDocument["tgRange"] = ATTENUATOR_RANGE + 21; // no SAW filter so 20dBm output is possible. + if ( AGC_On ) jsonDocument["PreAmp"] = 0x60; // Auto - else jsonDocument["PreAmp"] = setting.PreampGain; // Fixed gain @@ -579,7 +712,6 @@ static DynamicJsonDocument jsonDocument ( capacity ); // buffer for json data to serializeJson ( jsonDocument, wsBuffer ); webSocket.broadcastTXT ( wsBuffer ); // Send to all connected websocket clients } - else Serial.println ( "No buffer :("); @@ -593,14 +725,15 @@ static DynamicJsonDocument jsonDocument ( capacity ); // buffer for json data to void pushIFSweepSettings () { size_t capacity = JSON_ARRAY_SIZE ( SCREEN_WIDTH ) - + SCREEN_WIDTH*JSON_OBJECT_SIZE ( 2 ) + JSON_OBJECT_SIZE ( 13 ); + + SCREEN_WIDTH*JSON_OBJECT_SIZE ( 2 ) + JSON_OBJECT_SIZE ( 17 ); static DynamicJsonDocument jsonDocument ( capacity ); // buffer for json data to be pushed to the web clients jsonDocument["mType"] = "Settings"; + jsonDocument["mode"] = setting.Mode; jsonDocument["dispPoints"] = displayPoints; jsonDocument["start"] = startFreq_IF / 1000.0; jsonDocument["stop"] = stopFreq_IF / 1000.0; - jsonDocument["IF"] = sigFreq_IF / 1000000.0; + jsonDocument["IF"] = setting.IF_Freq / 1000000.0; jsonDocument["attenuation"] = setting.Attenuate; jsonDocument["extGain"] = setting.ExternalGain; jsonDocument["levelOffset"] = setting.LevelOffset; @@ -610,10 +743,21 @@ static DynamicJsonDocument jsonDocument ( capacity ); // buffer for json data to jsonDocument["Drive"] = setting.Drive; jsonDocument["sweepPoints"] = sweepPoints; jsonDocument["spur"] = setting.Spur; - + jsonDocument["tg"] = trackGenSetting.Mode; + jsonDocument["tgPower"] = trackGenSetting.Power; + jsonDocument["tgFreq"] = trackGenSetting.Frequency; + jsonDocument["sg"] = sigGenOutputOn; // + jsonDocument["sgPower"] = sigGenSetting.Power; + jsonDocument["sgMod"] = sigGenSetting.ModulationType; + jsonDocument["sgModFreq"] = sigGenSetting.ModFrequency; + jsonDocument["sgFreq"] = sigGenSetting.Frequency; + jsonDocument["sgCal"] = sigGenSetting.Calibration; + jsonDocument["sgRange"] = ATTENUATOR_RANGE + 11; // SI4432 output can be adjusted over 21dBm but max to SAW filter is 10dBm + jsonDocument["tgCal"] = trackGenSetting.Calibration; + jsonDocument["tgRange"] = ATTENUATOR_RANGE + 21; // no SAW filter so 20dBm output is possible. + if ( AGC_On ) jsonDocument["PreAmp"] = 0x60; // Auto - else jsonDocument["PreAmp"] = setting.PreampGain; // Fixed gain @@ -624,7 +768,6 @@ static DynamicJsonDocument jsonDocument ( capacity ); // buffer for json data to serializeJson ( jsonDocument, wsBuffer ); webSocket.broadcastTXT ( wsBuffer ); // Send to all connected websocket clients } - else Serial.println ( "No buffer :("); @@ -638,10 +781,11 @@ static DynamicJsonDocument jsonDocument ( capacity ); // buffer for json data to void pushRXSweepSettings () { size_t capacity = JSON_ARRAY_SIZE ( SCREEN_WIDTH ) - + SCREEN_WIDTH*JSON_OBJECT_SIZE ( 2 ) + JSON_OBJECT_SIZE ( 13 ); + + SCREEN_WIDTH*JSON_OBJECT_SIZE ( 2 ) + JSON_OBJECT_SIZE ( 17 ); static DynamicJsonDocument jsonDocument ( capacity ); // buffer for json data to be pushed to the web clients jsonDocument["mType"] = "Settings"; + jsonDocument["mode"] = setting.Mode; jsonDocument["dispPoints"] = displayPoints; jsonDocument["start"] = startFreq_RX / 1000.0; jsonDocument["stop"] = stopFreq_RX / 1000.0; @@ -655,10 +799,21 @@ static DynamicJsonDocument jsonDocument ( capacity ); // buffer for json data to jsonDocument["Drive"] = setting.Drive; jsonDocument["sweepPoints"] = sweepPoints; jsonDocument["spur"] = setting.Spur; - + jsonDocument["tg"] = trackGenSetting.Mode; + jsonDocument["tgPower"] = trackGenSetting.Power; + jsonDocument["tgFreq"] = trackGenSetting.Frequency; + jsonDocument["sg"] = sigGenOutputOn; // + jsonDocument["sgPower"] = sigGenSetting.Power; + jsonDocument["sgMod"] = sigGenSetting.ModulationType; + jsonDocument["sgModFreq"] = sigGenSetting.ModFrequency; + jsonDocument["sgFreq"] = sigGenSetting.Frequency; + jsonDocument["sgCal"] = sigGenSetting.Calibration; + jsonDocument["sgRange"] = ATTENUATOR_RANGE + 11; // SI4432 output can be adjusted over 21dBm but max to SAW filter is 10dBm + jsonDocument["tgCal"] = trackGenSetting.Calibration; + jsonDocument["tgRange"] = ATTENUATOR_RANGE + 21; // no SAW filter so 20dBm output is possible. + if ( AGC_On ) jsonDocument["PreAmp"] = 0x60; // Auto - else jsonDocument["PreAmp"] = setting.PreampGain; // Fixed gain @@ -669,7 +824,6 @@ static DynamicJsonDocument jsonDocument ( capacity ); // buffer for json data to serializeJson ( jsonDocument, wsBuffer ); webSocket.broadcastTXT ( wsBuffer ); // Send to all connected websocket clients } - else Serial.println ( "No buffer :("); @@ -683,10 +837,11 @@ static DynamicJsonDocument jsonDocument ( capacity ); // buffer for json data to void pushBandscopeSettings () { size_t capacity = JSON_ARRAY_SIZE ( SCREEN_WIDTH ) - + SCREEN_WIDTH*JSON_OBJECT_SIZE ( 2 ) + JSON_OBJECT_SIZE ( 13 ); + + SCREEN_WIDTH*JSON_OBJECT_SIZE ( 2 ) + JSON_OBJECT_SIZE ( 17 ); static DynamicJsonDocument jsonDocument ( capacity ); // buffer for json data to be pushed to the web clients jsonDocument["mType"] = "Settings"; + jsonDocument["mode"] = setting.Mode; jsonDocument["dispPoints"] = setting.BandscopePoints; jsonDocument["start"] = setting.BandscopeStart / 1000.0; jsonDocument["stop"] = ( setting.BandscopeStart + setting.BandscopeSpan ) / 1000.0; @@ -700,10 +855,21 @@ static DynamicJsonDocument jsonDocument ( capacity ); // buffer for json data to jsonDocument["Drive"] = setting.Drive; jsonDocument["sweepPoints"] = sweepPoints; jsonDocument["spur"] = setting.Spur; - + jsonDocument["tg"] = trackGenSetting.Mode; + jsonDocument["tgPower"] = trackGenSetting.Power; + jsonDocument["tgFreq"] = trackGenSetting.Frequency; + jsonDocument["sg"] = sigGenOutputOn; // + jsonDocument["sgPower"] = sigGenSetting.Power; + jsonDocument["sgMod"] = sigGenSetting.ModulationType; + jsonDocument["sgModFreq"] = sigGenSetting.ModFrequency; + jsonDocument["sgFreq"] = sigGenSetting.Frequency; + jsonDocument["sgCal"] = sigGenSetting.Calibration; + jsonDocument["sgRange"] = ATTENUATOR_RANGE + 11; // SI4432 output can be adjusted over 21dBm but max to SAW filter is 10dBm + jsonDocument["tgCal"] = trackGenSetting.Calibration; + jsonDocument["tgRange"] = ATTENUATOR_RANGE + 21; // no SAW filter so 20dBm output is possible. + if ( AGC_On ) jsonDocument["PreAmp"] = 0x60; // Auto - else jsonDocument["PreAmp"] = setting.PreampGain; // Fixed gain @@ -714,13 +880,74 @@ static DynamicJsonDocument jsonDocument ( capacity ); // buffer for json data to serializeJson ( jsonDocument, wsBuffer ); webSocket.broadcastTXT ( wsBuffer ); // Send to all connected websocket clients } - else Serial.println ( "No buffer :("); // Serial.printf ( "Push Settings sweepPoints %u\n", sweepPoints ); } + + +/* + * Push the settings data to the websocket clients + */ +void pushSigGenSettings () +{ +size_t capacity = JSON_ARRAY_SIZE ( SCREEN_WIDTH ) + + SCREEN_WIDTH*JSON_OBJECT_SIZE ( 2 ) + JSON_OBJECT_SIZE ( 17 ); +static DynamicJsonDocument jsonDocument ( capacity ); // buffer for json data to be pushed to the web clients + + jsonDocument["mType"] = "Settings"; + jsonDocument["mode"] = setting.Mode; + jsonDocument["dispPoints"] = displayPoints; + jsonDocument["start"] = startFreq_IF / 1000.0; + jsonDocument["stop"] = stopFreq_IF / 1000.0; + jsonDocument["IF"] = setting.IF_Freq / 1000000.0; + jsonDocument["attenuation"] = setting.Attenuate; + jsonDocument["extGain"] = setting.ExternalGain; + jsonDocument["levelOffset"] = setting.LevelOffset; + jsonDocument["setRBW"] = setting.Bandwidth10; + jsonDocument["bandwidth"] = bandwidth; + jsonDocument["RefOut"] = setting.ReferenceOut; + jsonDocument["Drive"] = setting.Drive; + jsonDocument["sweepPoints"] = sweepPoints; + jsonDocument["spur"] = setting.Spur; + jsonDocument["tg"] = trackGenSetting.Mode; + jsonDocument["tgPower"] = trackGenSetting.Power; + jsonDocument["tgMod"] = trackGenSetting.ModulationType; + jsonDocument["tgModFreq"] = trackGenSetting.ModFrequency; + jsonDocument["tgFreq"] = trackGenSetting.Frequency; + jsonDocument["sg"] = sigGenOutputOn; // + jsonDocument["sgPower"] = sigGenSetting.Power; + jsonDocument["sgMod"] = sigGenSetting.ModulationType; + jsonDocument["sgModFreq"] = sigGenSetting.ModFrequency; + jsonDocument["sgFreq"] = sigGenSetting.Frequency; + jsonDocument["sgCal"] = sigGenSetting.Calibration; + jsonDocument["sgRange"] = (ATTENUATOR_RANGE + RX_SI4432_MAX_DRIVE * 3); // SI4432 output can be adjusted over 21dBm but max to SAW filter is 10dBm + jsonDocument["tgCal"] = trackGenSetting.Calibration; + jsonDocument["tgRange"] = ATTENUATOR_RANGE + 21; // no SAW filter so full 20dBm output is possible. + + if ( AGC_On ) + jsonDocument["PreAmp"] = 0x60; // Auto + else + jsonDocument["PreAmp"] = setting.PreampGain; // Fixed gain + + String wsBuffer; + + if ( wsBuffer ) + { + serializeJson ( jsonDocument, wsBuffer ); + webSocket.broadcastTXT ( wsBuffer ); // Send to all connected websocket clients + } + else + Serial.println ( "No buffer :("); + +// Serial.printf ( "Push Settings sweepPoints %u\n", sweepPoints ); +} + + + + /* * Prepare a response ready for push to web clients */ diff --git a/simpleSA_wifi.h b/simpleSA_wifi.h index bf2265a..1536272 100644 --- a/simpleSA_wifi.h +++ b/simpleSA_wifi.h @@ -33,21 +33,26 @@ #include #include -#define SSID_NAME "TinySA" // Name of access point +#define SSID_NAME "simpleSA" // Name of access point /* * Function prototypes: */ - extern boolean startAP (); - extern boolean connectWiFi (); - extern void buildServer (); - extern void addTagNameValue ( char *b, char *_name, char *value ); - extern char *escapeXML ( char *s ); - extern void webSocketEvent ( uint8_t num, WStype_t type, uint8_t* payload, size_t lenght ); - extern char *FormatIPAddress ( IPAddress ipAddress ); - + boolean startAP (); + boolean connectWiFi (); + void buildServer (); + void addTagNameValue ( char *b, char *_name, char *value ); + char *escapeXML ( char *s ); + void webSocketEvent ( uint8_t num, WStype_t type, uint8_t* payload, size_t lenght ); + char *FormatIPAddress ( IPAddress ipAddress ); + void pushSettings (); + void pushIFSweepSettings (); + void pushRXSweepSettings (); + void pushBandscopeSettings (); + void pushSigGenSettings (); + void initChunkSweepDoc (uint32_t startIndex); /* * Functions outside of "TinySA_wifi: diff --git a/ui.cpp b/ui.cpp index 2f031ee..bb37242 100644 --- a/ui.cpp +++ b/ui.cpp @@ -197,7 +197,7 @@ uint8_t operation_requested = OP_NONE; // No operations so far enum { KM_START, KM_STOP, KM_CENTER, KM_SPAN, KM_FOCUS, KM_REFPOS, KM_ATTENUATION, KM_ACTUALPOWER, KM_IFFREQ, KM_PREAMP, KM_TUNE, KM_SGFREQ, KM_SGLEVEL, KM_SGLEVCAL, KM_IFSTART, KM_IFSTOP, - KM_IFSIG, KM_TGOFFSET, KM_TGLO_DRIVE, KM_TGIF_DRIVE, KM_BANDSCOPESTART, + KM_IFSIG, KM_TGOFFSET, KM_TGFREQ, KM_TGLO_DRIVE, KM_TGIF_DRIVE, KM_BANDSCOPESTART, KM_WFMIN, KM_WFGAIN, KM_BANDSCOPELEVEL, KM_RXSPAN, KM_RXSIG, KM_RBW, KM_EXTERN }; @@ -216,7 +216,7 @@ static const char * const keypad_mode_label[] = "START", "STOP", "CENTER", "SPAN", "FOCUS", "REFPOS", "ATTEN", "POWER", "IF FREQ", "PREAMP", "XTAL CAL", "SG FREQ", "dBm", "Max dBm", "IF START", "IF STOP", - "IF Sig Freq", "TG OFFSET", "TG LO Drive", "TG IF Drive", "START", + "IF Sig Freq", "TG OFFSET", "TG FREQ", "TG LO Drive", "TG IF Drive", "START", "WF MIN", "WF GAIN", "REF LEVEL", "RX SPAN", "RX Sig Freq", "RBW", "EXTERNAL" }; @@ -291,6 +291,7 @@ static void menu_WaterfallGain_cb ( int item ); static void menu_tracking_cb(int item); // M0WID - added in 3.0e static void menu_tg_offset_cb(int item); // M0WID - added in 3.0e +static void menu_tg_frequency_cb(int item); // M0WID - added in 3.0e static void menu_tgIF_drive_cb(int item); // M0WID - added in 3.0e static void menu_tgLO_drive_cb(int item); // M0WID - added in 3.0e @@ -489,11 +490,13 @@ static Menuitem menu_tracking[] = // Tracking generator mode { Menuitem ( MT_FUNC, "OFF", menu_tracking_cb ), Menuitem ( MT_FUNC, "ON", menu_tracking_cb ), - Menuitem ( MT_FUNC, "OFFSET", menu_tg_offset_cb ), - Menuitem ( MT_FUNC, "\2IF\0DRIVE", menu_tgIF_drive_cb ), #ifdef SI_TG_LO_CS + Menuitem ( MT_FUNC, "GENERATE", menu_tracking_cb ), + Menuitem ( MT_FUNC, "FREQUENCY",menu_tg_frequency_cb ), + Menuitem ( MT_FUNC, "OFFSET", menu_tg_offset_cb ), Menuitem ( MT_FUNC, "\2LO\0DRIVE", menu_tgLO_drive_cb ), #endif + Menuitem ( MT_FUNC, "\2IF\0DRIVE", menu_tgIF_drive_cb ), Menuitem ( MT_BACK, "<-BACK" ), // Next level up Menuitem ( MT_END ) // End marker }; @@ -1168,7 +1171,7 @@ void ShowSplash ( void ) tft.setFreeFont ( &FreeSansBold9pt7b ); // Select Free Serif 9 point font tft.drawString ( "By WA2FZW, M0WID,", 160, 60 ); tft.drawString ( "VK3PE and G3ZQC", 160, 80 ); - tft.drawString ( "Version 0.01", 160, 100 ); + tft.drawString ( PROGRAM_VERSION, 160, 100 ); tft.drawString ( "Original tinySA by Erik (PD0EK)", 160, 120 ); tft.setTextDatum ( TL_DATUM ); // Back to default top left @@ -1387,6 +1390,17 @@ void menu_tg_offset_cb ( int item ) ui_process_keypad (); } +/* + * "menu_tg_frequency_cb" - Handles setting the tracking generator frequency when in sig gen mode + */ + +void menu_tg_frequency_cb ( int item ) +{ + int km = KM_TGFREQ; + tft.fillScreen ( bg ); + ui_mode_keypad ( km ); + ui_process_keypad (); +} /* @@ -1449,6 +1463,11 @@ static void menu_tracking_cb (int item ) ui_mode_normal (); // Back to sweep break; + case 2: // Turn Sig gen mode + SetTracking (2); + ui_mode_normal (); // Back to sweep + break; + } } @@ -2132,6 +2151,7 @@ static const keypads_t * const keypads_mode_tbl[] = keypads_freq, // KM_IFSTOP.........IF Sweep stop frequency keypads_freq, // KM_IFSIG..........IF Sweep signal frequency keypads_signed_freq, // KM_TGOFFSET.......Offset Frequency of TG IF compared to SA IF + keypads_freq, // KM_TGFREQ.........Frequency of TG in sig gen mode keypads_level, // KM_TGLO_DRIVE.....Tracking generator LO drive keypads_level, // KM_TGIF_DRIVE.....Tracking generator IF drive keypads_freq, // KM_BANDSCOPESTART.IF Sweep start frequency @@ -2521,6 +2541,10 @@ static void fetch_numeric_target ( void ) uistat.value = trackGenSetting.Offset; break; + case KM_TGFREQ: + uistat.value = trackGenSetting.Frequency; + break; + case KM_TGIF_DRIVE: uistat.value = trackGenSetting.IF_Drive; break; @@ -2944,6 +2968,23 @@ static int keypad_click ( int key ) SetTGOffset ( (int32_t)value ); break; + + case KM_TGFREQ: + if ( (value > MAX_SIGLO_FREQ) || (value < MIN_SIGLO_FREQ) ) + { + strcpy ( fBuff, FormatSignedFrequency (( int32_t ) value )); + + DisplayError ( ERR_WARN, + fBuff, + "Invalid Frequency!", + NULL, + NULL ); + } + else + SetTGFreq ( (int32_t)value ); + break; + + case KM_TGIF_DRIVE: if ( (value > MAX_DRIVE) || (value < MIN_DRIVE) ) { @@ -2957,6 +2998,8 @@ static int keypad_click ( int key ) SetTGIfDrive ( (uint8_t)value ); break; + +#ifdef SI_TG_LO_CS case KM_TGLO_DRIVE: if ( (value > MAX_DRIVE) || (value < MIN_DRIVE) ) { @@ -2969,7 +3012,8 @@ static int keypad_click ( int key ) else SetTGLoDrive ( (uint8_t)value ); break; - +#endif + case KM_BANDSCOPESTART: // Bandscope Start frequency entered? SetBandscopeStart (( int32_t ) value ); @@ -3227,21 +3271,25 @@ void UiProcessTouch ( void ) if ( (touch_y < 10) && (touch_x < 160) ) { marker[0].Toggle(); // marker 1 + setting.MkrStatus[0] = marker[0].Status(); return; } else if ( (touch_y < 10) && (touch_x > 160) ) { marker[2].Toggle(); // marker 3 + setting.MkrStatus[2] = marker[2].Status(); return; } else if ( (touch_y < 20) && (touch_x < 160) ) { marker[1].Toggle(); // marker 2 + setting.MkrStatus[1] = marker[1].Status(); return; } else if ( (touch_y < 20) && (touch_x > 160) ) { marker[3].Toggle(); // marker 4 + setting.MkrStatus[3] = marker[3].Status(); return; } else if ( (touch_y < 40) && (touch_x > 30) )