mirror of
https://github.com/mudita/MuditaOS.git
synced 2026-04-25 17:44:03 -04:00
373 lines
9.9 KiB
C++
373 lines
9.9 KiB
C++
/*
|
|
* ServiceEink.cpp
|
|
*
|
|
* Created on: 22 maj 2019
|
|
* Author: robert
|
|
*/
|
|
|
|
//FreeRTOS
|
|
extern "C" {
|
|
#include "FreeRTOS.h"
|
|
#include "task.h"
|
|
#include "queue.h"
|
|
#include "timers.h"
|
|
#include "semphr.h"
|
|
}
|
|
//module-utils
|
|
#include "log/log.hpp"
|
|
//module-vfs
|
|
#include "vfs.hpp"
|
|
#include "EinkIncludes.hpp"
|
|
|
|
//eink messages
|
|
#include "messages/EinkMessage.hpp"
|
|
#include "messages/ImageMessage.hpp"
|
|
#include "service-gui/messages/GUIMessage.hpp"
|
|
|
|
#include "SystemManager/SystemManager.hpp"
|
|
|
|
#include "MessageType.hpp"
|
|
|
|
#include "ServiceEink.hpp"
|
|
|
|
enum class EinkWorkerCommands {
|
|
Initialize,
|
|
Initialized,
|
|
Destroy,
|
|
CopyImage,
|
|
CopyCompleteCallback,
|
|
CopyComplete
|
|
};
|
|
|
|
|
|
/// This is DMA handle for internal frame buffer memory-to-memory copying operation
|
|
//static edma_handle_t s_einkMemcpyDma_handle;
|
|
|
|
/**
|
|
* @brief This function is a callback for the memory to memory Eink HW copying completed event
|
|
* @param
|
|
*/
|
|
static void s_EinkServiceDMAMemcpyCallback(edma_handle_t *handle, void *param, bool transferDone, uint32_t tcds)
|
|
{
|
|
if (isIRQ())
|
|
{
|
|
BaseType_t xhigherpriorityTaskToBeWokenUp = 0;
|
|
xTaskNotifyFromISR((TaskHandle_t)param, 0, eNoAction, &xhigherpriorityTaskToBeWokenUp);
|
|
portEND_SWITCHING_ISR( xhigherpriorityTaskToBeWokenUp );
|
|
}
|
|
else
|
|
{
|
|
xTaskNotify((TaskHandle_t)param, 0, eNoAction);
|
|
}
|
|
}
|
|
|
|
ServiceEink::ServiceEink(const std::string& name)
|
|
: sys::Service(name),
|
|
timerID { 0 },
|
|
selfRefereshTriggerCount{ 0 },
|
|
temperatureMeasurementTriggerCount{ 0 },
|
|
powerOffTriggerCount{ 0 }
|
|
{
|
|
//initialize initial eink parameters
|
|
memset(&waveformSettings, 0, sizeof(EinkWaveFormSettings_t));
|
|
waveformSettings.mode = EinkWaveformGC16;
|
|
waveformSettings.temperature = -1000;
|
|
}
|
|
|
|
ServiceEink::~ServiceEink(){
|
|
LOG_INFO("[ServiceEink] Cleaning resources");
|
|
//release data from settings
|
|
if( waveformSettings.LUTCData != nullptr )
|
|
delete [] waveformSettings.LUTCData;
|
|
if( waveformSettings.LUTDData != nullptr )
|
|
delete [] waveformSettings.LUTDData;
|
|
//set sure that any new temperature will cause to load data from file.
|
|
waveformSettings.temperature = -1000;
|
|
|
|
}
|
|
|
|
// Invoked upon receiving data message
|
|
sys::Message_t ServiceEink::DataReceivedHandler(sys::DataMessage* msgl) {
|
|
seink::EinkMessage* msg = static_cast<seink::EinkMessage*>(msgl);
|
|
|
|
switch( msg->messageType ) {
|
|
|
|
case static_cast<uint32_t>(MessageType::MessageTypeUninitialized): {
|
|
LOG_ERROR("[ServiceEink] Received uninitialized message type");
|
|
} break;
|
|
|
|
case static_cast<uint32_t>(MessageType::EinkImageData): {
|
|
auto dmsg = static_cast<seink::ImageMessage*>( msgl );
|
|
LOG_ERROR("[ServiceEink] Received framebuffer");
|
|
memcpy( einkRenderBuffer, dmsg->getData(), dmsg->getSize() );
|
|
|
|
uint32_t start_tick = xTaskGetTickCount();
|
|
EinkPowerOn();
|
|
|
|
int32_t temperature = EinkGetTemperatureInternal();
|
|
|
|
changeWaveform( EinkWaveforms_e::EinkWaveformDU2, temperature );
|
|
|
|
EinkStatus_e ret =
|
|
EinkUpdateFrame ( 0,
|
|
0,
|
|
480,
|
|
600,
|
|
einkRenderBuffer,
|
|
Eink4Bpp,
|
|
EinkDisplayColorModeStandard );
|
|
if( ret != EinkOK )
|
|
LOG_FATAL("Failed to update frame");
|
|
|
|
ret = EinkRefreshImage (0, 0, 480, 600, EinkDisplayTimingsFastRefreshMode );
|
|
|
|
if( ret != EinkOK )
|
|
LOG_FATAL("Failed to refresh frame");
|
|
EinkPowerOff();
|
|
uint32_t end_tick = xTaskGetTickCount();
|
|
|
|
LOG_INFO("[ServiceEink] RefreshTime: %d", end_tick - start_tick);
|
|
|
|
auto msg = std::make_shared<sgui::GUIMessage>(MessageType::GUIDisplayReady );
|
|
sys::Bus::SendUnicast(msg, "ServiceGUI", this);
|
|
} break;
|
|
|
|
case static_cast<uint32_t>(MessageType::EinkTemperatureUpdate): {
|
|
|
|
} break;
|
|
|
|
case static_cast<uint32_t>(MessageType::EinkStateRequest ): {
|
|
auto msg = std::make_shared<sgui::GUIMessage>(MessageType::GUIDisplayReady );
|
|
sys::Bus::SendUnicast(msg, "ServiceGUI", this);
|
|
} break;
|
|
|
|
};
|
|
|
|
return std::make_shared<sys::ResponseMessage>();
|
|
}
|
|
|
|
// Invoked when timer ticked
|
|
void ServiceEink::TickHandler(uint32_t id) {
|
|
|
|
LOG_INFO("[ServiceEink] Timer");
|
|
}
|
|
|
|
// Invoked during initialization
|
|
sys::ReturnCodes ServiceEink::InitHandler() {
|
|
|
|
LOG_INFO("[ServiceEink] Initializing");
|
|
|
|
EinkStatus_e einkStatus = EinkResetAndInitialize();
|
|
|
|
if (einkStatus != EinkOK)
|
|
{
|
|
LOG_FATAL("Error: Could not initialize Eink display!\n");
|
|
}
|
|
|
|
EinkMemcpyDmaInit( s_EinkServiceDMAMemcpyCallback );
|
|
|
|
//TODO remove screen clearing code below.
|
|
EinkPowerOn();
|
|
|
|
uint8_t s_einkAmbientTemperature = EinkGetTemperatureInternal();
|
|
LOG_INFO("EInk measured temperature: %d\u00B0C", s_einkAmbientTemperature);
|
|
|
|
// Make the saturation to the lower limit
|
|
if (s_einkAmbientTemperature < 0)
|
|
s_einkAmbientTemperature = 0;
|
|
|
|
// Make the saturation to the higher limit
|
|
if (s_einkAmbientTemperature > 49)
|
|
s_einkAmbientTemperature = 49;
|
|
|
|
// Clear the temperature timer count
|
|
deepClearScreen( s_einkAmbientTemperature );
|
|
EinkPowerOff();
|
|
|
|
//TODO remove and add timer or turning off eink
|
|
EinkPowerOn();
|
|
|
|
auto msg = std::make_shared<sgui::GUIMessage>(MessageType::GUIDisplayReady );
|
|
sys::Bus::SendUnicast(msg, "ServiceGUI", this);
|
|
|
|
|
|
return sys::ReturnCodes::Success;
|
|
}
|
|
|
|
sys::ReturnCodes ServiceEink::DeinitHandler() {
|
|
return sys::ReturnCodes::Success;
|
|
}
|
|
|
|
sys::ReturnCodes ServiceEink::WakeUpHandler() {
|
|
return sys::ReturnCodes::Success;
|
|
}
|
|
|
|
|
|
sys::ReturnCodes ServiceEink::SleepHandler() {
|
|
return sys::ReturnCodes::Success;
|
|
}
|
|
|
|
bool ServiceEink::changeWaveform( EinkWaveforms_e mode, const int32_t temperature ) {
|
|
|
|
// If neither the temperature nor the waveform has changed - do nothing
|
|
if ((temperature == waveformSettings.temperature) &&
|
|
(mode == waveformSettings.mode ))
|
|
{
|
|
return EinkOK;
|
|
}
|
|
|
|
const uint32_t LUTD_SIZE = 16385;
|
|
const uint32_t LUTC_SIZE = 64;
|
|
const uint32_t LUTR_SIZE = 256; ///< Needed due to \ref EINK_LUTS_FILE_PATH structure
|
|
|
|
const uint32_t LUTS_TOTAL_SIZE = LUTD_SIZE + LUTC_SIZE + LUTR_SIZE;
|
|
|
|
waveformSettings.temperature = temperature;
|
|
|
|
unsigned int segment = 0;
|
|
|
|
if (temperature < 38)
|
|
{
|
|
segment = temperature/3;
|
|
}
|
|
else
|
|
{
|
|
if (temperature < 43)
|
|
{
|
|
segment = 12;
|
|
}
|
|
else
|
|
{
|
|
segment = 13;
|
|
}
|
|
}
|
|
|
|
uint32_t offset = 0;
|
|
|
|
switch (mode)
|
|
{
|
|
case EinkWaveformINIT:
|
|
offset = LUTS_TOTAL_SIZE*segment;
|
|
break;
|
|
|
|
case EinkWaveformA2:
|
|
offset = LUTS_TOTAL_SIZE*(14+segment);
|
|
break;
|
|
|
|
case EinkWaveformDU2:
|
|
offset = LUTS_TOTAL_SIZE*(28+segment);
|
|
break;
|
|
|
|
case EinkWaveformGLD16:
|
|
offset = LUTS_TOTAL_SIZE*(42+segment);
|
|
break;
|
|
|
|
case EinkWaveformGC16:
|
|
default:
|
|
offset = LUTS_TOTAL_SIZE*(56+segment);
|
|
break;
|
|
}
|
|
|
|
|
|
//Open file
|
|
auto file = vfs.fopen( "sys/Luts.bin", "rb" );
|
|
if ( file == nullptr )
|
|
{
|
|
LOG_FATAL("Could not find the LUTS.bin file. Returning");
|
|
return false;
|
|
}
|
|
// Allocate memory for the LUTD data. +1 for the EinkLUTD command for SPI transfer
|
|
if( waveformSettings.LUTDData != nullptr )
|
|
delete [] waveformSettings.LUTDData;
|
|
|
|
waveformSettings.LUTDSize = 0;
|
|
waveformSettings.LUTDData = new uint8_t[ LUTD_SIZE + 1];
|
|
|
|
if(waveformSettings.LUTDData == nullptr )
|
|
{
|
|
LOG_ERROR("Could not allocate memory for the LUTD array");
|
|
vfs.fclose( file );
|
|
return false;
|
|
}
|
|
|
|
// Allocate memory for the LUTC data. +1 for the EinkLUTC command for SPI transfer
|
|
if( waveformSettings.LUTCData != nullptr )
|
|
delete [] waveformSettings.LUTCData;
|
|
|
|
waveformSettings.LUTCSize = LUTC_SIZE;
|
|
waveformSettings.LUTCData = new uint8_t[ LUTC_SIZE + 1];
|
|
if ( waveformSettings.LUTCData == nullptr )
|
|
{
|
|
LOG_ERROR("Could not allocate memory for the LUTC array");
|
|
vfs.fclose( file );
|
|
return false;
|
|
}
|
|
|
|
waveformSettings.LUTDData[0] = EinkLUTD;
|
|
waveformSettings.LUTCData[0] = EinkLUTC;
|
|
|
|
///LUTD
|
|
vfs.fseek( file, offset, SEEK_SET );
|
|
vfs.fread( &waveformSettings.LUTDData[1], 1, LUTD_SIZE, file );
|
|
|
|
uint8_t frameCount = waveformSettings.LUTDData[1] + 1; // 0x00 - 1 frame, ... , 0x0F - 16 frames
|
|
waveformSettings.LUTDSize = frameCount * 64 + 1 + 1; // (frameCount * 64) - size of actual LUT; (+1) - the byte containing frameCount; (+1) - EinkLUTD command
|
|
|
|
//LUTC
|
|
offset += LUTD_SIZE;
|
|
vfs.fseek( file, offset, SEEK_SET );
|
|
vfs.fread( &waveformSettings.LUTCData[1], 1, LUTC_SIZE, file );
|
|
|
|
vfs.fclose( file );
|
|
|
|
EinkUpdateWaveform( &waveformSettings );
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ServiceEink::deepClearScreen(int8_t temperature)
|
|
{
|
|
EinkWaveforms_e wv = waveformSettings.mode;
|
|
|
|
// changeWaveform( EinkWaveforms_e::EinkWaveformA2, temperature );
|
|
// EinkFillScreenWithColor(EinkDisplayColorWhite);
|
|
// EinkFillScreenWithColor(EinkDisplayColorBlack);
|
|
// EinkFillScreenWithColor(EinkDisplayColorWhite);
|
|
// EinkFillScreenWithColor(EinkDisplayColorBlack);
|
|
// EinkFillScreenWithColor(EinkDisplayColorWhite);
|
|
|
|
EinkPowerOn();
|
|
changeWaveform( EinkWaveforms_e::EinkWaveformA2, temperature );
|
|
|
|
EinkStatus_e ret;
|
|
memset( einkRenderBuffer, 15, 480*600 );
|
|
ret = EinkUpdateFrame ( 0,0, 480, 600, einkRenderBuffer, Eink4Bpp, EinkDisplayColorModeStandard );
|
|
if( ret != EinkOK ) LOG_FATAL("Failed to update frame");
|
|
ret = EinkRefreshImage (0, 0, 480, 600, EinkDisplayTimingsFastRefreshMode );
|
|
if( ret != EinkOK ) LOG_FATAL("Failed to refresh frame");
|
|
|
|
for( uint32_t i=0; i<2; i++) {
|
|
memset( einkRenderBuffer, 0, 480*600 );
|
|
ret = EinkUpdateFrame ( 0,0, 480, 600, einkRenderBuffer, Eink4Bpp, EinkDisplayColorModeStandard );
|
|
if( ret != EinkOK ) LOG_FATAL("Failed to update frame");
|
|
ret = EinkRefreshImage (0, 0, 480, 600, EinkDisplayTimingsFastRefreshMode );
|
|
if( ret != EinkOK ) LOG_FATAL("Failed to refresh frame");
|
|
|
|
memset( einkRenderBuffer, 15, 480*600 );
|
|
ret = EinkUpdateFrame ( 0,0, 480, 600, einkRenderBuffer, Eink4Bpp, EinkDisplayColorModeStandard );
|
|
if( ret != EinkOK ) LOG_FATAL("Failed to update frame");
|
|
ret = EinkRefreshImage (0, 0, 480, 600, EinkDisplayTimingsFastRefreshMode );
|
|
if( ret != EinkOK ) LOG_FATAL("Failed to refresh frame");
|
|
}
|
|
|
|
changeWaveform(wv, temperature);
|
|
|
|
EinkPowerOff();
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
|