mirror of
https://github.com/armel/uv-k1-k5v3-firmware-custom.git
synced 2026-10-02 03:15:37 +00:00
SPI flash driver (write) & settings saving
This commit is contained in:
1 parent
992a417e62
commit
a5690b5bf4
14 files changed
+562
-151
No files matched your search
+3
-2
@@ -12,7 +12,6 @@ target_sources(App INTERFACE
|
||||
driver/gpio.c
|
||||
driver/i2c.c
|
||||
driver/keyboard.c
|
||||
# driver/spi.c
|
||||
driver/st7565.c
|
||||
driver/system.c
|
||||
driver/systick.c
|
||||
@@ -106,7 +105,9 @@ enable_feature(ENABLE_AIRCOPY
|
||||
ui/aircopy.c
|
||||
)
|
||||
enable_feature(ENABLE_NOAA)
|
||||
# enable_feature(ENABLE_VOICE)
|
||||
enable_feature(ENABLE_VOICE
|
||||
driver/dac.c
|
||||
)
|
||||
enable_feature(ENABLE_VOX)
|
||||
enable_feature(ENABLE_ALARM)
|
||||
enable_feature(ENABLE_TX1750)
|
||||
|
||||
+1
-6
@@ -119,12 +119,7 @@ void FM_TurnOff(void)
|
||||
|
||||
void FM_EraseChannels(void)
|
||||
{
|
||||
uint8_t Template[8];
|
||||
memset(Template, 0xFF, sizeof(Template));
|
||||
|
||||
for (unsigned i = 0; i < 5; i++)
|
||||
EEPROM_WriteBuffer(0x0E40 + (i * 8), Template);
|
||||
|
||||
PY25Q16_SectorErase(0x003000);
|
||||
memset(gFM_Channels, 0xFF, sizeof(gFM_Channels));
|
||||
}
|
||||
|
||||
|
||||
+4
-1
@@ -328,7 +328,10 @@ static void CMD_051D(const uint8_t *pBuffer)
|
||||
bReloadEeprom = true;
|
||||
|
||||
if ((Offset < 0x0E98 || Offset >= 0x0EA0) || !bIsInLockScreen || pCmd->bAllowPassword)
|
||||
EEPROM_WriteBuffer(Offset, &pCmd->Data[i * 8U]);
|
||||
{
|
||||
// EEPROM_WriteBuffer(Offset, &pCmd->Data[i * 8U]);
|
||||
// TODO: To be implemented
|
||||
}
|
||||
}
|
||||
|
||||
if (bReloadEeprom)
|
||||
|
||||
+11
-1
@@ -25,6 +25,7 @@
|
||||
#include "py32f071_ll_gpio.h"
|
||||
#include "py32f071_ll_rcc.h"
|
||||
#include "py32f071_ll_adc.h"
|
||||
#include "driver/dac.h"
|
||||
#include "driver/backlight.h"
|
||||
#ifdef ENABLE_FMRADIO
|
||||
#include "driver/bk1080.h"
|
||||
@@ -110,15 +111,21 @@ void BOARD_GPIO_Init(void)
|
||||
InitStruct.Pin = LL_GPIO_PIN_9 | LL_GPIO_PIN_8 | LL_GPIO_PIN_2;
|
||||
LL_GPIO_Init(GPIOB, &InitStruct);
|
||||
|
||||
// TODO: conditional compile per ENABLE_FLASHLIGHT
|
||||
// Flashlight: PC13
|
||||
InitStruct.Pin = LL_GPIO_PIN_13;
|
||||
LL_GPIO_Init(GPIOC, &InitStruct);
|
||||
|
||||
#ifdef ENABLE_FMRADIO
|
||||
// BK1080 SCK: PF5
|
||||
// BK1080 SDA: PF6
|
||||
InitStruct.Pin = LL_GPIO_PIN_6 | LL_GPIO_PIN_5;
|
||||
LL_GPIO_Init(GPIOF, &InitStruct);
|
||||
#endif
|
||||
|
||||
// Backlight: PF8
|
||||
// BK4819 CS: PF9
|
||||
InitStruct.Pin = LL_GPIO_PIN_9 | LL_GPIO_PIN_8 | LL_GPIO_PIN_6 | LL_GPIO_PIN_5;
|
||||
InitStruct.Pin = LL_GPIO_PIN_9 | LL_GPIO_PIN_8 ;
|
||||
LL_GPIO_Init(GPIOF, &InitStruct);
|
||||
|
||||
#ifndef ENABLE_SWD
|
||||
@@ -172,6 +179,9 @@ void BOARD_Init(void)
|
||||
BOARD_GPIO_Init();
|
||||
BACKLIGHT_InitHardware();
|
||||
BOARD_ADC_Init();
|
||||
#ifdef ENABLE_VOICE
|
||||
DAC_Init();
|
||||
#endif
|
||||
PY25Q16_Init();
|
||||
ST7565_Init();
|
||||
#ifdef ENABLE_FMRADIO
|
||||
|
||||
@@ -81,6 +81,9 @@ static void BACKLIGHT_Sound(void)
|
||||
|
||||
void BACKLIGHT_TurnOn(void)
|
||||
{
|
||||
// TODO: This is temporary. Will delete
|
||||
GPIO_TurnOnBacklight();
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN_SLEEP
|
||||
gSleepModeCountdown_500ms = gSetting_set_off * 120;
|
||||
#endif
|
||||
|
||||
+2
-1
@@ -1,4 +1,5 @@
|
||||
/* Copyright 2023 Dual Tachyon
|
||||
/* Copyright 2025 muzkr https://github.com/muzkr
|
||||
* Copyright 2023 Dual Tachyon
|
||||
* https://github.com/DualTachyon
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
/* Copyright 2025 muzkr https://github.com/muzkr
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "driver/dac.h"
|
||||
#include "driver/systick.h"
|
||||
#include "py32f071_ll_bus.h"
|
||||
#include "py32f071_ll_gpio.h"
|
||||
#include "py32f071_ll_dac.h"
|
||||
#include "py32f071_ll_tim.h"
|
||||
|
||||
#define TIMx TIM6
|
||||
#define DAC_CHANNEL LL_DAC_CHANNEL_1
|
||||
|
||||
static inline void TIM_Init()
|
||||
{
|
||||
LL_TIM_SetPrescaler(TIMx, 3);
|
||||
LL_TIM_SetAutoReload(TIMx, 1499);
|
||||
LL_TIM_SetTriggerOutput(TIMx, LL_TIM_TRGO_UPDATE);
|
||||
}
|
||||
|
||||
void DAC_Init()
|
||||
{
|
||||
// Channel 1: PA4
|
||||
LL_IOP_GRP1_EnableClock(LL_IOP_GRP1_PERIPH_GPIOA);
|
||||
LL_GPIO_SetPinMode(GPIOA, LL_GPIO_PIN_4, LL_GPIO_MODE_ANALOG);
|
||||
|
||||
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_DAC1);
|
||||
LL_DAC_SetTriggerSource(DAC1, DAC_CHANNEL, LL_DAC_TRIG_EXT_TIM6_TRGO);
|
||||
LL_DAC_SetOutputBuffer(DAC1, DAC_CHANNEL, LL_DAC_OUTPUT_BUFFER_ENABLE);
|
||||
LL_DAC_EnableDMAReq(DAC1, DAC_CHANNEL);
|
||||
LL_DAC_Enable(DAC1, DAC_CHANNEL);
|
||||
|
||||
SYSTICK_DelayUs(15);
|
||||
|
||||
TIM_Init();
|
||||
|
||||
LL_DAC_EnableTrigger(DAC1, DAC_CHANNEL);
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
/* Copyright 2025 muzkr https://github.com/muzkr
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef DRIVER_DAC_H
|
||||
#define DRIVER_DAC_H
|
||||
|
||||
void DAC_Init();
|
||||
|
||||
#endif // DRIVER_DAC_H
|
||||
+245
-8
@@ -1,5 +1,5 @@
|
||||
/* Copyright 2023 Dual Tachyon
|
||||
* https://github.com/DualTachyon
|
||||
/* Copyright 2025 muzkr
|
||||
* https://github.com/muzkr
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "py32f071_ll_spi.h"
|
||||
#include "py32f071_ll_dma.h"
|
||||
#include "driver/system.h"
|
||||
#include "driver/systick.h"
|
||||
|
||||
#define SPIx SPI2
|
||||
#define CHANNEL_RD LL_DMA_CHANNEL_4
|
||||
@@ -31,7 +32,12 @@
|
||||
|
||||
#define CS_PIN GPIO_MAKE_PIN(GPIOA, LL_GPIO_PIN_3)
|
||||
|
||||
static uint8_t TX_Buf[256];
|
||||
#define SECTOR_SIZE 0x1000
|
||||
#define PAGE_SIZE 0x100
|
||||
|
||||
static uint32_t SectorCacheAddr = 0x1000000;
|
||||
static uint8_t SectorCache[SECTOR_SIZE];
|
||||
static uint8_t BlackHole[1];
|
||||
static volatile bool TC_Flag;
|
||||
|
||||
static inline void CS_Assert()
|
||||
@@ -126,7 +132,56 @@ static void SPI_ReadBuf(uint8_t *Buf, uint32_t Size)
|
||||
LL_DMA_SetPeriphAddress(DMA1, CHANNEL_RD, LL_SPI_DMA_GetRegAddr(SPIx));
|
||||
LL_DMA_SetDataLength(DMA1, CHANNEL_RD, Size);
|
||||
|
||||
LL_DMA_SetMemoryAddress(DMA1, CHANNEL_WR, (uint32_t)TX_Buf);
|
||||
LL_DMA_SetMemoryAddress(DMA1, CHANNEL_WR, (uint32_t)BlackHole);
|
||||
LL_DMA_SetPeriphAddress(DMA1, CHANNEL_WR, LL_SPI_DMA_GetRegAddr(SPIx));
|
||||
LL_DMA_SetDataLength(DMA1, CHANNEL_WR, Size);
|
||||
|
||||
TC_Flag = false;
|
||||
LL_DMA_EnableIT_TC(DMA1, CHANNEL_RD);
|
||||
LL_DMA_EnableChannel(DMA1, CHANNEL_RD);
|
||||
LL_DMA_EnableChannel(DMA1, CHANNEL_WR);
|
||||
|
||||
LL_SPI_EnableDMAReq_RX(SPIx);
|
||||
LL_SPI_Enable(SPIx);
|
||||
LL_SPI_EnableDMAReq_TX(SPIx);
|
||||
|
||||
while (!TC_Flag)
|
||||
;
|
||||
}
|
||||
|
||||
static void SPI_WriteBuf(const uint8_t *Buf, uint32_t Size)
|
||||
{
|
||||
LL_SPI_Disable(SPIx);
|
||||
LL_DMA_DisableChannel(DMA1, CHANNEL_RD);
|
||||
LL_DMA_DisableChannel(DMA1, CHANNEL_WR);
|
||||
|
||||
LL_DMA_ClearFlag_GI4(DMA1);
|
||||
|
||||
LL_DMA_ConfigTransfer(DMA1, CHANNEL_RD, //
|
||||
LL_DMA_DIRECTION_PERIPH_TO_MEMORY //
|
||||
| LL_DMA_MODE_NORMAL //
|
||||
| LL_DMA_PERIPH_NOINCREMENT //
|
||||
| LL_DMA_MEMORY_NOINCREMENT //
|
||||
| LL_DMA_PDATAALIGN_BYTE //
|
||||
| LL_DMA_MDATAALIGN_BYTE //
|
||||
| LL_DMA_PRIORITY_LOW //
|
||||
);
|
||||
|
||||
LL_DMA_ConfigTransfer(DMA1, CHANNEL_WR, //
|
||||
LL_DMA_DIRECTION_MEMORY_TO_PERIPH //
|
||||
| LL_DMA_MODE_NORMAL //
|
||||
| LL_DMA_PERIPH_NOINCREMENT //
|
||||
| LL_DMA_MEMORY_INCREMENT //
|
||||
| LL_DMA_PDATAALIGN_BYTE //
|
||||
| LL_DMA_MDATAALIGN_BYTE //
|
||||
| LL_DMA_PRIORITY_LOW //
|
||||
);
|
||||
|
||||
LL_DMA_SetMemoryAddress(DMA1, CHANNEL_RD, (uint32_t)BlackHole);
|
||||
LL_DMA_SetPeriphAddress(DMA1, CHANNEL_RD, LL_SPI_DMA_GetRegAddr(SPIx));
|
||||
LL_DMA_SetDataLength(DMA1, CHANNEL_RD, Size);
|
||||
|
||||
LL_DMA_SetMemoryAddress(DMA1, CHANNEL_WR, (uint32_t)Buf);
|
||||
LL_DMA_SetPeriphAddress(DMA1, CHANNEL_WR, LL_SPI_DMA_GetRegAddr(SPIx));
|
||||
LL_DMA_SetDataLength(DMA1, CHANNEL_WR, Size);
|
||||
|
||||
@@ -153,6 +208,14 @@ static uint8_t SPI_WriteByte(uint8_t Value)
|
||||
return LL_SPI_ReceiveData8(SPIx);
|
||||
}
|
||||
|
||||
static void WriteAddr(uint32_t Addr);
|
||||
static uint8_t ReadStatusReg(uint32_t Which);
|
||||
static void WaitWIP();
|
||||
static void WriteEnable();
|
||||
static void SectorErase(uint32_t Addr);
|
||||
static void SectorProgram(uint32_t Addr, const uint8_t *Buf, uint32_t Size);
|
||||
static void PageProgram(uint32_t Addr, const uint8_t *Buf, uint32_t Size);
|
||||
|
||||
void PY25Q16_Init()
|
||||
{
|
||||
CS_Release();
|
||||
@@ -164,9 +227,7 @@ void PY25Q16_ReadBuffer(uint32_t Address, void *pBuffer, uint32_t Size)
|
||||
CS_Assert();
|
||||
|
||||
SPI_WriteByte(0x03); // Fast read
|
||||
SPI_WriteByte(0xff & (Address >> 16));
|
||||
SPI_WriteByte(0xff & (Address >> 8));
|
||||
SPI_WriteByte(0xff & Address);
|
||||
WriteAddr(Address);
|
||||
|
||||
if (Size >= 16)
|
||||
{
|
||||
@@ -183,8 +244,184 @@ void PY25Q16_ReadBuffer(uint32_t Address, void *pBuffer, uint32_t Size)
|
||||
CS_Release();
|
||||
}
|
||||
|
||||
void PY25Q16_WriteBuffer(uint16_t Address, const void *pBuffer)
|
||||
void PY25Q16_WriteBuffer(uint32_t Address, const void *pBuffer, uint32_t Size, bool Append)
|
||||
{
|
||||
while (Size)
|
||||
{
|
||||
uint32_t SecIndex = Address / SECTOR_SIZE;
|
||||
uint32_t SecOffset = Address % SECTOR_SIZE;
|
||||
uint32_t SecSize = SECTOR_SIZE - SecOffset;
|
||||
if (Size < SecSize)
|
||||
{
|
||||
SecSize = Size;
|
||||
}
|
||||
|
||||
uint32_t SecAddr = SecIndex * SECTOR_SIZE;
|
||||
if (SecAddr != SectorCacheAddr)
|
||||
{
|
||||
PY25Q16_ReadBuffer(SecAddr, SectorCache, SECTOR_SIZE);
|
||||
SectorCacheAddr = SecAddr;
|
||||
}
|
||||
|
||||
if (0 != strncmp(pBuffer, (char *)SectorCache + SecOffset, SecSize))
|
||||
{
|
||||
bool Erase = false;
|
||||
for (uint32_t i = 0; i < SecSize; i++)
|
||||
{
|
||||
if (0xff != SectorCache[SecOffset + i])
|
||||
{
|
||||
Erase = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(SectorCache + SecOffset, pBuffer, SecSize);
|
||||
|
||||
if (Erase)
|
||||
{
|
||||
SectorErase(SecAddr);
|
||||
if (Append)
|
||||
{
|
||||
SectorProgram(SecAddr, SectorCache, SecOffset + SecSize);
|
||||
memset(SectorCache + SecOffset + SecSize, 0xff, SECTOR_SIZE - SecOffset - SecSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
SectorProgram(SecAddr, SectorCache, SECTOR_SIZE);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SectorProgram(Address, pBuffer, SecSize);
|
||||
}
|
||||
}
|
||||
|
||||
Address += SecSize;
|
||||
pBuffer += SecSize;
|
||||
Size -= SecSize;
|
||||
} // while
|
||||
}
|
||||
|
||||
void PY25Q16_SectorErase(uint32_t Address)
|
||||
{
|
||||
Address -= (Address % SECTOR_SIZE);
|
||||
SectorErase(Address);
|
||||
if (SectorCacheAddr == Address)
|
||||
{
|
||||
memset(SectorCache, 0xff, SECTOR_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void WriteAddr(uint32_t Addr)
|
||||
{
|
||||
SPI_WriteByte(0xff & (Addr >> 16));
|
||||
SPI_WriteByte(0xff & (Addr >> 8));
|
||||
SPI_WriteByte(0xff & Addr);
|
||||
}
|
||||
|
||||
static uint8_t ReadStatusReg(uint32_t Which)
|
||||
{
|
||||
uint8_t Cmd;
|
||||
switch (Which)
|
||||
{
|
||||
case 0:
|
||||
Cmd = 0x5;
|
||||
break;
|
||||
case 1:
|
||||
Cmd = 0x35;
|
||||
break;
|
||||
case 2:
|
||||
Cmd = 0x15;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
CS_Assert();
|
||||
SPI_WriteByte(Cmd);
|
||||
uint8_t Value = SPI_WriteByte(0xff);
|
||||
CS_Release();
|
||||
|
||||
return Value;
|
||||
}
|
||||
|
||||
static void WaitWIP()
|
||||
{
|
||||
for (int i = 0; i < 1000000; i++)
|
||||
{
|
||||
uint8_t Status = ReadStatusReg(0);
|
||||
if (1 & Status) // WIP
|
||||
{
|
||||
SYSTICK_DelayUs(10);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void WriteEnable()
|
||||
{
|
||||
CS_Assert();
|
||||
SPI_WriteByte(0x6);
|
||||
CS_Release();
|
||||
}
|
||||
|
||||
static void SectorErase(uint32_t Addr)
|
||||
{
|
||||
WriteEnable();
|
||||
WaitWIP();
|
||||
|
||||
CS_Assert();
|
||||
SPI_WriteByte(0x20);
|
||||
WriteAddr(Addr);
|
||||
CS_Release();
|
||||
|
||||
WaitWIP();
|
||||
}
|
||||
|
||||
static void SectorProgram(uint32_t Addr, const uint8_t *Buf, uint32_t Size)
|
||||
{
|
||||
while (Size)
|
||||
{
|
||||
uint32_t Size1 = PAGE_SIZE - (Addr % PAGE_SIZE);
|
||||
if (Size < Size1)
|
||||
{
|
||||
Size1 = Size;
|
||||
}
|
||||
|
||||
PageProgram(Addr, Buf, Size1);
|
||||
|
||||
Addr += Size1;
|
||||
Buf += Size1;
|
||||
Size -= Size1;
|
||||
}
|
||||
}
|
||||
|
||||
static void PageProgram(uint32_t Addr, const uint8_t *Buf, uint32_t Size)
|
||||
{
|
||||
WriteEnable();
|
||||
WaitWIP();
|
||||
|
||||
CS_Assert();
|
||||
|
||||
SPI_WriteByte(0x2);
|
||||
WriteAddr(Addr);
|
||||
|
||||
if (Size >= 16)
|
||||
{
|
||||
SPI_WriteBuf(Buf, Size);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (uint32_t i = 0; i < Size; i++)
|
||||
{
|
||||
SPI_WriteByte(Buf[i]);
|
||||
}
|
||||
}
|
||||
|
||||
CS_Release();
|
||||
|
||||
WaitWIP();
|
||||
}
|
||||
|
||||
void DMA1_Channel4_5_6_7_IRQHandler()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* Copyright 2023 Dual Tachyon
|
||||
* https://github.com/DualTachyon
|
||||
/* Copyright 2025 muzkr
|
||||
* https://github.com/muzkr
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -18,11 +18,11 @@
|
||||
#define DRIVER_PY25Q16_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
void PY25Q16_Init();
|
||||
void PY25Q16_ReadBuffer(uint32_t Address, void *pBuffer, uint32_t Size);
|
||||
void PY25Q16_WriteBuffer(uint16_t Address, const void *pBuffer);
|
||||
|
||||
#define EEPROM_WriteBuffer PY25Q16_WriteBuffer
|
||||
void PY25Q16_WriteBuffer(uint32_t Address, const void *pBuffer, uint32_t Size, bool Append);
|
||||
void PY25Q16_SectorErase(uint32_t Address);
|
||||
|
||||
#endif
|
||||
+29
-26
@@ -74,22 +74,22 @@ static void SPI_Init()
|
||||
LL_SPI_Enable(SPIx);
|
||||
}
|
||||
|
||||
static inline void AssertCS()
|
||||
static inline void CS_Assert()
|
||||
{
|
||||
GPIO_ResetOutputPin(PIN_CS);
|
||||
}
|
||||
|
||||
static inline void ReleaseCS()
|
||||
static inline void CS_Release()
|
||||
{
|
||||
GPIO_SetOutputPin(PIN_CS);
|
||||
}
|
||||
|
||||
static inline void SetA0()
|
||||
static inline void A0_Set()
|
||||
{
|
||||
GPIO_SetOutputPin(PIN_A0);
|
||||
}
|
||||
|
||||
static inline void ResetA0()
|
||||
static inline void A0_Reset()
|
||||
{
|
||||
GPIO_ResetOutputPin(PIN_A0);
|
||||
}
|
||||
@@ -110,7 +110,7 @@ static uint8_t SPI_WriteByte(uint8_t Value)
|
||||
static void DrawLine(uint8_t column, uint8_t line, const uint8_t * lineBuffer, unsigned size_defVal)
|
||||
{
|
||||
ST7565_SelectColumnAndLine(column + 4, line);
|
||||
SetA0();
|
||||
A0_Set();
|
||||
for (unsigned i = 0; i < size_defVal; i++) {
|
||||
SPI_WriteByte(lineBuffer ? lineBuffer[i] : size_defVal);
|
||||
}
|
||||
@@ -118,9 +118,9 @@ static void DrawLine(uint8_t column, uint8_t line, const uint8_t * lineBuffer, u
|
||||
|
||||
void ST7565_DrawLine(const unsigned int Column, const unsigned int Line, const uint8_t *pBitmap, const unsigned int Size)
|
||||
{
|
||||
AssertCS();
|
||||
CS_Assert();
|
||||
DrawLine(Column, Line, pBitmap, Size);
|
||||
ReleaseCS();
|
||||
CS_Release();
|
||||
}
|
||||
|
||||
|
||||
@@ -134,7 +134,7 @@ void ST7565_DrawLine(const unsigned int Column, const unsigned int Line, const u
|
||||
|
||||
static void ST7565_BlitScreen(uint8_t line)
|
||||
{
|
||||
AssertCS();
|
||||
CS_Assert();
|
||||
ST7565_WriteByte(0x40);
|
||||
|
||||
if(line == 0)
|
||||
@@ -152,7 +152,7 @@ void ST7565_DrawLine(const unsigned int Column, const unsigned int Line, const u
|
||||
}
|
||||
}
|
||||
|
||||
ReleaseCS();
|
||||
CS_Release();
|
||||
}
|
||||
|
||||
void ST7565_BlitFullScreen(void)
|
||||
@@ -172,38 +172,38 @@ void ST7565_DrawLine(const unsigned int Column, const unsigned int Line, const u
|
||||
#else
|
||||
void ST7565_BlitFullScreen(void)
|
||||
{
|
||||
AssertCS();
|
||||
CS_Assert();
|
||||
ST7565_WriteByte(0x40);
|
||||
for (unsigned line = 0; line < FRAME_LINES; line++) {
|
||||
DrawLine(0, line+1, gFrameBuffer[line], LCD_WIDTH);
|
||||
}
|
||||
ReleaseCS();
|
||||
CS_Release();
|
||||
}
|
||||
|
||||
void ST7565_BlitLine(unsigned line)
|
||||
{
|
||||
AssertCS();
|
||||
CS_Assert();
|
||||
ST7565_WriteByte(0x40); // start line ?
|
||||
DrawLine(0, line+1, gFrameBuffer[line], LCD_WIDTH);
|
||||
ReleaseCS();
|
||||
CS_Release();
|
||||
}
|
||||
|
||||
void ST7565_BlitStatusLine(void)
|
||||
{ // the top small text line on the display
|
||||
AssertCS();
|
||||
CS_Assert();
|
||||
ST7565_WriteByte(0x40); // start line ?
|
||||
DrawLine(0, 0, gStatusLine, LCD_WIDTH);
|
||||
ReleaseCS();
|
||||
CS_Release();
|
||||
}
|
||||
#endif
|
||||
|
||||
void ST7565_FillScreen(uint8_t value)
|
||||
{
|
||||
AssertCS();
|
||||
CS_Assert();
|
||||
for (unsigned i = 0; i < 8; i++) {
|
||||
DrawLine(0, i, NULL, value);
|
||||
}
|
||||
ReleaseCS();
|
||||
CS_Release();
|
||||
}
|
||||
|
||||
// Software reset
|
||||
@@ -289,7 +289,7 @@ uint8_t cmds[] = {
|
||||
#if defined(ENABLE_FEAT_F4HWN_CTR) || defined(ENABLE_FEAT_F4HWN_INV)
|
||||
void ST7565_ContrastAndInv(void)
|
||||
{
|
||||
AssertCS();
|
||||
CS_Assert();
|
||||
ST7565_WriteByte(ST7565_CMD_SOFTWARE_RESET); // software reset
|
||||
|
||||
for(uint8_t i = 0; i < 8; i++)
|
||||
@@ -327,7 +327,7 @@ void ST7565_Init(void)
|
||||
{
|
||||
SPI_Init();
|
||||
ST7565_HardwareReset();
|
||||
AssertCS();
|
||||
CS_Assert();
|
||||
ST7565_WriteByte(ST7565_CMD_SOFTWARE_RESET); // software reset
|
||||
SYSTEM_DelayMs(120);
|
||||
|
||||
@@ -353,7 +353,7 @@ void ST7565_Init(void)
|
||||
ST7565_WriteByte(ST7565_CMD_SET_START_LINE | 0); // line 0
|
||||
ST7565_WriteByte(ST7565_CMD_DISPLAY_ON_OFF | 1); // D=1
|
||||
|
||||
ReleaseCS();
|
||||
CS_Release();
|
||||
|
||||
ST7565_FillScreen(0x00);
|
||||
}
|
||||
@@ -361,17 +361,17 @@ void ST7565_Init(void)
|
||||
#ifdef ENABLE_FEAT_F4HWN_SLEEP
|
||||
void ST7565_ShutDown(void)
|
||||
{
|
||||
AssertCS();
|
||||
CS_Assert();
|
||||
ST7565_WriteByte(ST7565_CMD_POWER_CIRCUIT | 0b000); // VB=0 VR=1 VF=1
|
||||
ST7565_WriteByte(ST7565_CMD_SET_START_LINE | 0); // line 0
|
||||
ST7565_WriteByte(ST7565_CMD_DISPLAY_ON_OFF | 0); // D=1
|
||||
ReleaseCS();
|
||||
CS_Release();
|
||||
}
|
||||
#endif
|
||||
|
||||
void ST7565_FixInterfGlitch(void)
|
||||
{
|
||||
AssertCS();
|
||||
CS_Assert();
|
||||
for(uint8_t i = 0; i < ARRAY_SIZE(cmds); i++)
|
||||
#ifdef ENABLE_FEAT_F4HWN
|
||||
ST7565_Cmd(i);
|
||||
@@ -379,7 +379,7 @@ void ST7565_FixInterfGlitch(void)
|
||||
ST7565_WriteByte(cmds[i]);
|
||||
#endif
|
||||
|
||||
ReleaseCS();
|
||||
CS_Release();
|
||||
}
|
||||
|
||||
void ST7565_HardwareReset(void)
|
||||
@@ -390,14 +390,17 @@ void ST7565_HardwareReset(void)
|
||||
|
||||
void ST7565_SelectColumnAndLine(uint8_t Column, uint8_t Line)
|
||||
{
|
||||
ResetA0();
|
||||
A0_Reset();
|
||||
SPI_WriteByte(Line + 176);
|
||||
SPI_WriteByte(((Column >> 4) & 0x0F) | 0x10);
|
||||
SPI_WriteByte((Column >> 0) & 0x0F);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a command (rather than pixel data)
|
||||
*/
|
||||
void ST7565_WriteByte(uint8_t Value)
|
||||
{
|
||||
ResetA0();
|
||||
A0_Reset();
|
||||
SPI_WriteByte(Value);
|
||||
}
|
||||
+184
-100
@@ -1,4 +1,5 @@
|
||||
/* Copyright 2023 Dual Tachyon
|
||||
/* Copyright 2025 muzkr https://github.com/muzkr
|
||||
* Copyright 2023 Dual Tachyon
|
||||
* https://github.com/DualTachyon
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -502,33 +503,54 @@ void SETTINGS_FetchChannelName(char *s, const int channel)
|
||||
|
||||
void SETTINGS_FactoryReset(bool bIsAll)
|
||||
{
|
||||
uint16_t i;
|
||||
uint8_t Template[8];
|
||||
|
||||
memset(Template, 0xFF, sizeof(Template));
|
||||
|
||||
//for (i = 0x0C80; i < 0x1E00; i += 8)
|
||||
for (i = 0x0000; i < 0x1E00; i += 8)
|
||||
// 0000 - 0c80
|
||||
PY25Q16_SectorErase(0);
|
||||
// 0c80 - 0d60
|
||||
PY25Q16_SectorErase(0x001000);
|
||||
// 0d60 - 0e30
|
||||
if (bIsAll)
|
||||
{
|
||||
if (
|
||||
!(i >= 0x0EE0 && i < 0x0F18) && // ANI ID + DTMF codes
|
||||
!(i >= 0x0F30 && i < 0x0F50) && // AES KEY + F LOCK + Scramble Enable
|
||||
!(i >= 0x1C00 && i < 0x1E00) && // DTMF contacts
|
||||
!(i >= 0x0EB0 && i < 0x0ED0) && // Welcome strings
|
||||
!(i >= 0x0EA0 && i < 0x0EA8) && // Voice Prompt
|
||||
(bIsAll ||
|
||||
(
|
||||
!(i >= 0x0D60 && i < 0x0E28) && // MR Channel Attributes
|
||||
!(i >= 0x0F18 && i < 0x0F30) && // Scan List
|
||||
!(i >= 0x0F50 && i < 0x1C00) && // MR Channel Names
|
||||
!(i >= 0x0E40 && i < 0x0E70) && // FM Channels
|
||||
!(i >= 0x0E88 && i < 0x0E90) // FM settings
|
||||
))
|
||||
)
|
||||
{
|
||||
EEPROM_WriteBuffer(i, Template);
|
||||
}
|
||||
PY25Q16_SectorErase(0x002000);
|
||||
}
|
||||
// 0e40 - 0e68
|
||||
if (bIsAll)
|
||||
{
|
||||
PY25Q16_SectorErase(0x003000);
|
||||
}
|
||||
// 0e70 - 0e80
|
||||
PY25Q16_SectorErase(0x004000);
|
||||
// 0e80 - 0e88
|
||||
PY25Q16_SectorErase(0x005000);
|
||||
// 0e88 - 0e90
|
||||
if (bIsAll)
|
||||
{
|
||||
PY25Q16_SectorErase(0x006000);
|
||||
}
|
||||
// 0e90 - 0ee0
|
||||
do
|
||||
{
|
||||
uint8_t Buf[0x50];
|
||||
memset(Buf, 0xff, 0x50);
|
||||
// 0EA0 - 0EA8 : keep
|
||||
PY25Q16_ReadBuffer(0x007000 + 0x10, Buf + 0x10, 8);
|
||||
// 0EB0 - 0ED0 : keep
|
||||
PY25Q16_ReadBuffer(0x007000 + 0x20, Buf + 0x20, 0x20);
|
||||
PY25Q16_WriteBuffer(0x007000, Buf, 0x50, true);
|
||||
} while (0);
|
||||
// 0ee0 - 0f18 : keep
|
||||
// 0f18 - 0f20
|
||||
if (bIsAll)
|
||||
{
|
||||
PY25Q16_SectorErase(0x009000);
|
||||
}
|
||||
// 0f30 - 0f40 : keep
|
||||
// 0f40 - 0f48 : keep
|
||||
// 0f50 - 1bd0
|
||||
if (bIsAll)
|
||||
{
|
||||
PY25Q16_SectorErase(0x00e000);
|
||||
}
|
||||
// 1c00 - 1d00 : keep
|
||||
|
||||
if (bIsAll)
|
||||
{
|
||||
@@ -547,7 +569,7 @@ void SETTINGS_FactoryReset(bool bIsAll)
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN
|
||||
EEPROM_WriteBuffer(0x1FF0, Template);
|
||||
PY25Q16_SectorErase(0x00c000);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -571,11 +593,12 @@ void SETTINGS_SaveFM(void)
|
||||
fmCfg.selFreq = gEeprom.FM_SelectedFrequency;
|
||||
fmCfg.isMrMode = gEeprom.FM_IsMrMode;
|
||||
fmCfg.band = gEeprom.FM_Band;
|
||||
//fmCfg.space = gEeprom.FM_Space;
|
||||
EEPROM_WriteBuffer(0x0E88, fmCfg.__raw);
|
||||
// fmCfg.space = gEeprom.FM_Space;
|
||||
// 0E88
|
||||
PY25Q16_WriteBuffer(0x006000, fmCfg.__raw, 8, true);
|
||||
|
||||
for (unsigned i = 0; i < 5; i++)
|
||||
EEPROM_WriteBuffer(0x0E40 + (i * 8), &gFM_Channels[i * 4]);
|
||||
// 0E40
|
||||
PY25Q16_WriteBuffer(0x003000, gFM_Channels, sizeof(gFM_Channels), true);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -599,18 +622,23 @@ void SETTINGS_SaveVfoIndices(void)
|
||||
State[7] = gEeprom.NoaaChannel[1];
|
||||
#endif
|
||||
|
||||
EEPROM_WriteBuffer(0x0E80, State);
|
||||
// 0x0E80
|
||||
PY25Q16_WriteBuffer(0x005000, State, 8, true);
|
||||
}
|
||||
|
||||
void SETTINGS_SaveSettings(void)
|
||||
{
|
||||
uint8_t State[8];
|
||||
uint8_t *State;
|
||||
uint8_t tmp = 0;
|
||||
uint8_t SecBuf[0x50];
|
||||
|
||||
#ifdef ENABLE_PWRON_PASSWORD
|
||||
uint32_t Password[2];
|
||||
#endif
|
||||
// ----------------------
|
||||
// 0e70 - 0e80
|
||||
|
||||
memset(SecBuf, 0xff, 0x10);
|
||||
|
||||
// 0x0E70
|
||||
State = SecBuf;
|
||||
State[0] = gEeprom.CHAN_1_CALL;
|
||||
State[1] = gEeprom.SQUELCH_LEVEL;
|
||||
State[2] = gEeprom.TX_TIMEOUT_TIMER;
|
||||
@@ -634,8 +662,9 @@ void SETTINGS_SaveSettings(void)
|
||||
State[6] = 0;
|
||||
#endif
|
||||
State[7] = gEeprom.MIC_SENSITIVITY;
|
||||
EEPROM_WriteBuffer(0x0E70, State);
|
||||
|
||||
// 0x0E78
|
||||
State = SecBuf + 0x8;
|
||||
State[0] = (gEeprom.BACKLIGHT_MIN << 4) + gEeprom.BACKLIGHT_MAX;
|
||||
State[1] = gEeprom.CHANNEL_DISPLAY_MODE;
|
||||
State[2] = gEeprom.CROSS_BAND_RX_TX;
|
||||
@@ -671,8 +700,17 @@ void SETTINGS_SaveSettings(void)
|
||||
#else
|
||||
State[7] = gEeprom.VFO_OPEN;
|
||||
#endif
|
||||
EEPROM_WriteBuffer(0x0E78, State);
|
||||
|
||||
PY25Q16_WriteBuffer(0x004000, SecBuf, 0x10, true);
|
||||
|
||||
// -------------------------
|
||||
// 0e90 - 0ee0
|
||||
|
||||
// memset(SecBuf, 0xff, 0x50);
|
||||
PY25Q16_ReadBuffer(0x007000, SecBuf, 0x50);
|
||||
|
||||
// 0x0E90
|
||||
State = SecBuf;
|
||||
State[0] = gEeprom.BEEP_CONTROL;
|
||||
State[0] |= gEeprom.KEY_M_LONG_PRESS_ACTION << 1;
|
||||
State[1] = gEeprom.KEY_1_SHORT_PRESS_ACTION;
|
||||
@@ -682,15 +720,15 @@ void SETTINGS_SaveSettings(void)
|
||||
State[5] = gEeprom.SCAN_RESUME_MODE;
|
||||
State[6] = gEeprom.AUTO_KEYPAD_LOCK;
|
||||
State[7] = gEeprom.POWER_ON_DISPLAY_MODE;
|
||||
EEPROM_WriteBuffer(0x0E90, State);
|
||||
|
||||
// 0x0E98
|
||||
#ifdef ENABLE_PWRON_PASSWORD
|
||||
memset(Password, 0xFF, sizeof(Password));
|
||||
Password[0] = gEeprom.POWER_ON_PASSWORD;
|
||||
EEPROM_WriteBuffer(0x0E98, Password);
|
||||
State = SecBuf + 0x8;
|
||||
State[0] = gEeprom.POWER_ON_PASSWORD;
|
||||
#endif
|
||||
|
||||
memset(State, 0xFF, sizeof(State));
|
||||
// 0x0EA0
|
||||
State = SecBuf + 0x10;
|
||||
#ifdef ENABLE_VOICE
|
||||
State[0] = gEeprom.VOICE_PROMPT;
|
||||
#endif
|
||||
@@ -698,9 +736,9 @@ void SETTINGS_SaveSettings(void)
|
||||
State[1] = gEeprom.S0_LEVEL;
|
||||
State[2] = gEeprom.S9_LEVEL;
|
||||
#endif
|
||||
EEPROM_WriteBuffer(0x0EA0, State);
|
||||
|
||||
|
||||
// 0x0EA8
|
||||
State = SecBuf + 0x18;
|
||||
#if defined(ENABLE_ALARM) || defined(ENABLE_TX1750)
|
||||
State[0] = gEeprom.ALARM_MODE;
|
||||
#else
|
||||
@@ -710,8 +748,9 @@ void SETTINGS_SaveSettings(void)
|
||||
State[2] = gEeprom.REPEATER_TAIL_TONE_ELIMINATION;
|
||||
State[3] = gEeprom.TX_VFO;
|
||||
State[4] = gEeprom.BATTERY_TYPE;
|
||||
EEPROM_WriteBuffer(0x0EA8, State);
|
||||
|
||||
// 0x0ED0
|
||||
State = SecBuf + 0x40;
|
||||
State[0] = gEeprom.DTMF_SIDE_TONE;
|
||||
#ifdef ENABLE_DTMF_CALLING
|
||||
State[1] = gEeprom.DTMF_SEPARATE_CODE;
|
||||
@@ -722,16 +761,24 @@ void SETTINGS_SaveSettings(void)
|
||||
State[5] = gEeprom.DTMF_PRELOAD_TIME / 10U;
|
||||
State[6] = gEeprom.DTMF_FIRST_CODE_PERSIST_TIME / 10U;
|
||||
State[7] = gEeprom.DTMF_HASH_CODE_PERSIST_TIME / 10U;
|
||||
EEPROM_WriteBuffer(0x0ED0, State);
|
||||
|
||||
memset(State, 0xFF, sizeof(State));
|
||||
// 0x0ED8
|
||||
State = SecBuf + 0x48;
|
||||
State[0] = gEeprom.DTMF_CODE_PERSIST_TIME / 10U;
|
||||
State[1] = gEeprom.DTMF_CODE_INTERVAL_TIME / 10U;
|
||||
#ifdef ENABLE_DTMF_CALLING
|
||||
State[2] = gEeprom.PERMIT_REMOTE_KILL;
|
||||
#endif
|
||||
EEPROM_WriteBuffer(0x0ED8, State);
|
||||
|
||||
PY25Q16_WriteBuffer(0x007000, SecBuf, 0x50, true);
|
||||
|
||||
// -------------------------
|
||||
// 0f18 - 0f20
|
||||
|
||||
memset(SecBuf, 0xff, 0x8);
|
||||
|
||||
// 0x0F18
|
||||
State = SecBuf;
|
||||
State[0] = gEeprom.SCAN_LIST_DEFAULT;
|
||||
|
||||
tmp = 0;
|
||||
@@ -750,9 +797,16 @@ void SETTINGS_SaveSettings(void)
|
||||
State[5] = gEeprom.SCANLIST_PRIORITY_CH2[1];
|
||||
State[6] = gEeprom.SCANLIST_PRIORITY_CH1[2];
|
||||
State[7] = gEeprom.SCANLIST_PRIORITY_CH2[2];
|
||||
EEPROM_WriteBuffer(0x0F18, State);
|
||||
|
||||
memset(State, 0xFF, sizeof(State));
|
||||
PY25Q16_WriteBuffer(0x009000, SecBuf, 8, true);
|
||||
|
||||
// ---------------------
|
||||
// 0f40 - 0f48
|
||||
|
||||
memset(SecBuf, 0xff, 8);
|
||||
|
||||
// 0x0F40
|
||||
State = SecBuf;
|
||||
State[0] = gSetting_F_LOCK;
|
||||
#ifndef ENABLE_FEAT_F4HWN
|
||||
State[1] = gSetting_350TX;
|
||||
@@ -784,12 +838,15 @@ void SETTINGS_SaveSettings(void)
|
||||
#endif
|
||||
State[7] = (State[7] & ~(3u << 6)) | ((gSetting_backlight_on_tx_rx & 3u) << 6);
|
||||
|
||||
EEPROM_WriteBuffer(0x0F40, State);
|
||||
PY25Q16_WriteBuffer(0x00b000, SecBuf, 8, true);
|
||||
|
||||
// ------------------
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN
|
||||
// 0x1FF0
|
||||
State = SecBuf;
|
||||
// TODO: TBD
|
||||
PY25Q16_ReadBuffer(0x00c000, State, sizeof(State));
|
||||
PY25Q16_ReadBuffer(0x00c000, State, 8);
|
||||
|
||||
//memset(State, 0xFF, sizeof(State));
|
||||
|
||||
@@ -830,7 +887,7 @@ void SETTINGS_SaveSettings(void)
|
||||
|
||||
gEeprom.KEY_LOCK_PTT = gSetting_set_lck;
|
||||
|
||||
EEPROM_WriteBuffer(0x1FF0, State);
|
||||
PY25Q16_WriteBuffer(0x00c000, SecBuf, 8, true);
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN_VOL
|
||||
@@ -845,45 +902,53 @@ void SETTINGS_SaveChannel(uint8_t Channel, uint8_t VFO, const VFO_Info_t *pVFO,
|
||||
return;
|
||||
#endif
|
||||
|
||||
uint16_t OffsetVFO = Channel * 16;
|
||||
// 0
|
||||
uint16_t OffsetVFO = 0 + Channel * 16;
|
||||
|
||||
if (IS_FREQ_CHANNEL(Channel)) { // it's a VFO, not a channel
|
||||
OffsetVFO = (VFO == 0) ? 0x0C80 : 0x0C90;
|
||||
// 0x0C80
|
||||
OffsetVFO = (VFO == 0) ? 0x001000 : 0x001010;
|
||||
OffsetVFO += (Channel - FREQ_CHANNEL_FIRST) * 32;
|
||||
}
|
||||
|
||||
if (Mode >= 2 || IS_FREQ_CHANNEL(Channel)) { // copy VFO to a channel
|
||||
union {
|
||||
typedef union {
|
||||
uint8_t _8[8];
|
||||
uint32_t _32[2];
|
||||
} State;
|
||||
} State_t;
|
||||
|
||||
State_t *State;
|
||||
|
||||
State._32[0] = pVFO->freq_config_RX.Frequency;
|
||||
State._32[1] = pVFO->TX_OFFSET_FREQUENCY;
|
||||
EEPROM_WriteBuffer(OffsetVFO + 0, State._32);
|
||||
uint8_t Buf[0x10];
|
||||
|
||||
State._8[0] = pVFO->freq_config_RX.Code;
|
||||
State._8[1] = pVFO->freq_config_TX.Code;
|
||||
State._8[2] = (pVFO->freq_config_TX.CodeType << 4) | pVFO->freq_config_RX.CodeType;
|
||||
State._8[3] = (pVFO->Modulation << 4) | pVFO->TX_OFFSET_FREQUENCY_DIRECTION;
|
||||
State._8[4] = 0
|
||||
State = (State_t *)Buf;
|
||||
State -> _32[0] = pVFO->freq_config_RX.Frequency;
|
||||
State -> _32[1] = pVFO->TX_OFFSET_FREQUENCY;
|
||||
|
||||
State = (State_t *)(Buf + 0x8);
|
||||
State -> _8[0] = pVFO->freq_config_RX.Code;
|
||||
State -> _8[1] = pVFO->freq_config_TX.Code;
|
||||
State -> _8[2] = (pVFO->freq_config_TX.CodeType << 4) | pVFO->freq_config_RX.CodeType;
|
||||
State -> _8[3] = (pVFO->Modulation << 4) | pVFO->TX_OFFSET_FREQUENCY_DIRECTION;
|
||||
State -> _8[4] = 0
|
||||
| (pVFO->TX_LOCK << 6)
|
||||
| (pVFO->BUSY_CHANNEL_LOCK << 5)
|
||||
| (pVFO->OUTPUT_POWER << 2)
|
||||
| (pVFO->CHANNEL_BANDWIDTH << 1)
|
||||
| (pVFO->FrequencyReverse << 0);
|
||||
State._8[5] = ((pVFO->DTMF_PTT_ID_TX_MODE & 7u) << 1)
|
||||
State -> _8[5] = ((pVFO->DTMF_PTT_ID_TX_MODE & 7u) << 1)
|
||||
#ifdef ENABLE_DTMF_CALLING
|
||||
| ((pVFO->DTMF_DECODING_ENABLE & 1u) << 0)
|
||||
#endif
|
||||
;
|
||||
State._8[6] = pVFO->STEP_SETTING;
|
||||
State -> _8[6] = pVFO->STEP_SETTING;
|
||||
#ifdef ENABLE_FEAT_F4HWN
|
||||
State._8[7] = 0;
|
||||
State -> _8[7] = 0;
|
||||
#else
|
||||
State._8[7] = pVFO->SCRAMBLING_TYPE;
|
||||
State -> _8[7] = pVFO->SCRAMBLING_TYPE;
|
||||
#endif
|
||||
EEPROM_WriteBuffer(OffsetVFO + 8, State._8);
|
||||
|
||||
PY25Q16_WriteBuffer(OffsetVFO, Buf, 0x10, false);
|
||||
|
||||
SETTINGS_UpdateChannel(Channel, pVFO, true, true, true);
|
||||
|
||||
@@ -903,13 +968,14 @@ void SETTINGS_SaveChannel(uint8_t Channel, uint8_t VFO, const VFO_Info_t *pVFO,
|
||||
|
||||
void SETTINGS_SaveBatteryCalibration(const uint16_t * batteryCalibration)
|
||||
{
|
||||
uint16_t buf[4];
|
||||
EEPROM_WriteBuffer(0x1F40, batteryCalibration);
|
||||
uint16_t buf[8];
|
||||
memcpy(buf, batteryCalibration, 8);
|
||||
// 0x1F48
|
||||
PY25Q16_ReadBuffer(0x010000 + 0x148, buf, sizeof(buf));
|
||||
PY25Q16_ReadBuffer(0x010000 + 0x148, buf + 4, 8);
|
||||
buf[0] = batteryCalibration[4];
|
||||
buf[1] = batteryCalibration[5];
|
||||
EEPROM_WriteBuffer(0x1F48, buf);
|
||||
// 0x1F40
|
||||
PY25Q16_WriteBuffer(0x010000, buf, 0x10, false);
|
||||
}
|
||||
|
||||
void SETTINGS_SaveChannelName(uint8_t channel, const char * name)
|
||||
@@ -917,8 +983,8 @@ void SETTINGS_SaveChannelName(uint8_t channel, const char * name)
|
||||
uint16_t offset = channel * 16;
|
||||
uint8_t buf[16] = {0};
|
||||
memcpy(buf, name, MIN(strlen(name), 10u));
|
||||
EEPROM_WriteBuffer(0x0F50 + offset, buf);
|
||||
EEPROM_WriteBuffer(0x0F58 + offset, buf + 8);
|
||||
// 0x0F50
|
||||
PY25Q16_WriteBuffer(0x00e000 + offset, buf, 0x10, false);
|
||||
}
|
||||
|
||||
void SETTINGS_UpdateChannel(uint8_t channel, const VFO_Info_t *pVFO, bool keep, bool check, bool save)
|
||||
@@ -927,7 +993,7 @@ void SETTINGS_UpdateChannel(uint8_t channel, const VFO_Info_t *pVFO, bool keep,
|
||||
if (!IS_NOAA_CHANNEL(channel))
|
||||
#endif
|
||||
{
|
||||
uint8_t state[8];
|
||||
ChannelAttributes_t state;
|
||||
ChannelAttributes_t att = {
|
||||
.band = 0x7,
|
||||
.compander = 0,
|
||||
@@ -937,8 +1003,7 @@ void SETTINGS_UpdateChannel(uint8_t channel, const VFO_Info_t *pVFO, bool keep,
|
||||
}; // default attributes
|
||||
|
||||
// 0x0D60
|
||||
uint16_t offset = 0x002000 + (channel & ~7u);
|
||||
PY25Q16_ReadBuffer(offset, state, sizeof(state));
|
||||
PY25Q16_ReadBuffer(0x002000 + channel, &state, 1);
|
||||
|
||||
if (keep) {
|
||||
att.band = pVFO->Band;
|
||||
@@ -946,20 +1011,22 @@ void SETTINGS_UpdateChannel(uint8_t channel, const VFO_Info_t *pVFO, bool keep,
|
||||
att.scanlist2 = pVFO->SCANLIST2_PARTICIPATION;
|
||||
att.scanlist3 = pVFO->SCANLIST3_PARTICIPATION;
|
||||
att.compander = pVFO->Compander;
|
||||
if (check && state[channel & 7u] == att.__val)
|
||||
if (check && state.__val == att.__val)
|
||||
return; // no change in the attributes
|
||||
}
|
||||
|
||||
state[channel & 7u] = att.__val;
|
||||
state.__val = att.__val;
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN
|
||||
#ifndef ENABLE_FEAT_F4HWN
|
||||
save = true;
|
||||
#endif
|
||||
if(save)
|
||||
{
|
||||
EEPROM_WriteBuffer(offset, state);
|
||||
uint8_t buf[224];
|
||||
PY25Q16_ReadBuffer(0x002000, buf, sizeof(buf));
|
||||
buf[channel] = state.__val;
|
||||
PY25Q16_WriteBuffer(0x002000, buf, sizeof(buf), true);
|
||||
}
|
||||
#else
|
||||
EEPROM_WriteBuffer(offset, state);
|
||||
#endif
|
||||
|
||||
gMR_ChannelAttributes[channel] = att;
|
||||
|
||||
@@ -1031,18 +1098,18 @@ State[1] = 0
|
||||
| (1 << 6)
|
||||
#endif
|
||||
;
|
||||
EEPROM_WriteBuffer(0x1FF0, State);
|
||||
PY25Q16_WriteBuffer(0x00c000, State, sizeof(State), true);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN_RESUME_STATE
|
||||
void SETTINGS_WriteCurrentState(void)
|
||||
{
|
||||
uint8_t State[8];
|
||||
uint8_t State[0x10];
|
||||
// 0x0E78
|
||||
PY25Q16_ReadBuffer(0x004000 + 0x8, State, sizeof(State));
|
||||
//State[3] = (gEeprom.CURRENT_STATE << 4) | (gEeprom.BATTERY_SAVE & 0x0F);
|
||||
State[7] = (gEeprom.VFO_OPEN & 0x01) | ((gEeprom.CURRENT_STATE & 0x07) << 1) | ((gEeprom.SCAN_LIST_DEFAULT & 0x07) << 4);
|
||||
EEPROM_WriteBuffer(0x0E78, State);
|
||||
PY25Q16_ReadBuffer(0x004000, State, sizeof(State));
|
||||
//State[11] = (gEeprom.CURRENT_STATE << 4) | (gEeprom.BATTERY_SAVE & 0x0F);
|
||||
State[15] = (gEeprom.VFO_OPEN & 0x01) | ((gEeprom.CURRENT_STATE & 0x07) << 1) | ((gEeprom.SCAN_LIST_DEFAULT & 0x07) << 4);
|
||||
PY25Q16_WriteBuffer(0x004000, State, sizeof(State), true);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1053,20 +1120,37 @@ State[1] = 0
|
||||
// 0x1F88
|
||||
PY25Q16_ReadBuffer(0x010000 + 0x188, State, sizeof(State));
|
||||
State[6] = gEeprom.VOLUME_GAIN;
|
||||
EEPROM_WriteBuffer(0x1F88, State);
|
||||
PY25Q16_WriteBuffer(0x010000 + 0x188, State, sizeof(State), false);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN
|
||||
void SETTINGS_ResetTxLock(void)
|
||||
{
|
||||
uint8_t State[8];
|
||||
for(uint8_t channel = 0; channel < 200; channel++)
|
||||
// TODO: This is expensive operation!
|
||||
|
||||
#define SETTINGS_ResetTxLock_BATCH 10
|
||||
|
||||
uint8_t Buf[0xc80 / SETTINGS_ResetTxLock_BATCH];
|
||||
const uint32_t BatchSize = 0xc80 / SETTINGS_ResetTxLock_BATCH;
|
||||
const uint32_t BatchChCnt = BatchSize / 0x10;
|
||||
|
||||
for (uint32_t i = 0; i < SETTINGS_ResetTxLock_BATCH; i++)
|
||||
{
|
||||
uint16_t OffsetVFO = channel * 16;
|
||||
PY25Q16_ReadBuffer(OffsetVFO + 8, State, sizeof(State));
|
||||
State[4] |= (1 << 6);
|
||||
EEPROM_WriteBuffer(OffsetVFO + 8, State);
|
||||
uint32_t Offset = i * BatchSize;
|
||||
PY25Q16_ReadBuffer(0 + Offset, Buf, sizeof(Buf));
|
||||
|
||||
uint8_t *State;
|
||||
for (uint8_t channel = 0; channel < BatchChCnt; channel++)
|
||||
{
|
||||
uint16_t OffsetVFO = channel * 16;
|
||||
State = Buf + OffsetVFO;
|
||||
State[4] |= (1 << 6);
|
||||
}
|
||||
|
||||
PY25Q16_WriteBuffer(0 + Offset, Buf, sizeof(Buf), false);
|
||||
}
|
||||
|
||||
#undef SETTINGS_ResetTxLock_BATCH
|
||||
}
|
||||
#endif
|
||||
+3
-1
@@ -50,12 +50,14 @@ else()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(${TARGET})
|
||||
if(TARGET)
|
||||
set(EXE_NAME ${TARGET})
|
||||
else()
|
||||
set(EXE_NAME "firmware")
|
||||
endif()
|
||||
|
||||
message("EXE_NAME = " ${EXE_NAME})
|
||||
|
||||
add_executable(${EXE_NAME})
|
||||
|
||||
add_subdirectory(Drivers)
|
||||
|
||||
@@ -75,6 +75,7 @@
|
||||
"name": "Custom",
|
||||
"inherits": "Broadcast",
|
||||
"cacheVariables": {
|
||||
"ENABLE_VOICE": false,
|
||||
"ENABLE_SWD": true,
|
||||
"ENABLE_AIRCOPY": false
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user