TextLayer MultiColor PebbleSDK - pebble-watch

Is there any way to set the textlayer color on a pebble watchface to multiple colors? For instance, if the time is 12:00 I would like the 1 to be one color, the 2 to be a second color, the : to be the first color and so on and so forth. I cannot find this information anywhere, and the method seems to only take a single variable.

It is easy to do, you need to change the context color each time, In example:
void time_update_callback(Layer *layer, GContext *ctx)
{
/* Get a layer rect to re-draw */
GRect layer_bounds = layer_get_bounds(layer);
/* Get time from variables */
char h1[2];
char h2[2];
char m1[2];
char m2[2];
h1[0] = hour_text_visible[0];
h2[0] = hour_text_visible[1];
m1[0] = minute_text_visible[0];
m2[0] = minute_text_visible[1];
h1[1] = h2[1] = m1[1] = m2[1] = 0;
/* Add y padding to GRect */
layer_bounds.origin.y += 1;
/* Aux copy */
GRect origin = layer_bounds;
/* Change color to Black */
graphics_context_set_text_color(ctx, GColorBlack);
/* Move */
layer_bounds.origin.x += 4;
layer_bounds.origin.y += 1;
/* Draw assuming you have a font loaded */
graphics_draw_text(ctx, h1, font, layer_bounds, GTextOverflowModeTrailingEllipsis, GTextAlignmentLeft, NULL);
/* Move again */
layer_bounds.origin.x += 20;
/* Draw black also */
graphics_draw_text(ctx, h2, font, layer_bounds, GTextOverflowModeTrailingEllipsis, GTextAlignmentLeft, NULL);
/* move */
layer_bounds.origin.x += 30;
/* Change color to Blue */
graphics_context_set_text_color(ctx, GColorBlue);
/* Draw in blue */
graphics_draw_text(ctx, m1, font, layer_bounds, GTextOverflowModeTrailingEllipsis, GTextAlignmentLeft, NULL);
/* etc */
}

Related

STM32F429 FMC SDRAM issue when column adress > 8bit

I have the issue with FMC controller when interfacing 64MB IS42S16400J-7BLI.
I'm using the CubeMX to set base configuration
static void MX_FMC_Init(void)
{
FMC_SDRAM_TimingTypeDef SdramTiming;
/** Perform the SDRAM1 memory initialization sequence
*/
hsdram1.Instance = FMC_SDRAM_DEVICE;
/* hsdram1.Init */
hsdram1.Init.SDBank = FMC_SDRAM_BANK1;
hsdram1.Init.ColumnBitsNumber = FMC_SDRAM_COLUMN_BITS_NUM_11;
hsdram1.Init.RowBitsNumber = FMC_SDRAM_ROW_BITS_NUM_12;
hsdram1.Init.MemoryDataWidth = FMC_SDRAM_MEM_BUS_WIDTH_16;
hsdram1.Init.InternalBankNumber = FMC_SDRAM_INTERN_BANKS_NUM_4;
hsdram1.Init.CASLatency = FMC_SDRAM_CAS_LATENCY_3;
hsdram1.Init.WriteProtection = FMC_SDRAM_WRITE_PROTECTION_DISABLE;
hsdram1.Init.SDClockPeriod = FMC_SDRAM_CLOCK_PERIOD_2;
hsdram1.Init.ReadBurst = FMC_SDRAM_RBURST_DISABLE;
hsdram1.Init.ReadPipeDelay = FMC_SDRAM_RPIPE_DELAY_0;
/* SdramTiming */
SdramTiming.LoadToActiveDelay = 2;
SdramTiming.ExitSelfRefreshDelay = 7;
SdramTiming.SelfRefreshTime = 4;
SdramTiming.RowCycleDelay = 7;
SdramTiming.WriteRecoveryTime = 3;
SdramTiming.RPDelay = 2;
SdramTiming.RCDDelay = 2;
if (HAL_SDRAM_Init(&hsdram1, &SdramTiming) != HAL_OK)
{
Error_Handler();
}
}
and config the memory
void SDRAM_Initialization_Sequence(SDRAM_HandleTypeDef* hsdram, FMC_SDRAM_CommandTypeDef* Command)
{
__IO uint32_t tmpmrd = 0;
/* Step 3: Configure a clock configuration enable command */
Command->CommandMode = FMC_SDRAM_CMD_CLK_ENABLE;
Command->CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
Command->AutoRefreshNumber = 1;
Command->ModeRegisterDefinition = 0;
/* Send the command */
HAL_SDRAM_SendCommand(hsdram, Command, 0x1000);
/* Step 4: Insert 100 ms delay */
HAL_Delay(100);
/* Step 5: Configure a PALL (precharge all) command */
Command->CommandMode = FMC_SDRAM_CMD_PALL;
Command->CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
Command->AutoRefreshNumber = 1;
Command->ModeRegisterDefinition = 0;
/* Send the command */
HAL_SDRAM_SendCommand(hsdram, Command, 0x1000);
/* Step 6 : Configure a Auto-Refresh command */
Command->CommandMode = FMC_SDRAM_CMD_AUTOREFRESH_MODE;
Command->CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
Command->AutoRefreshNumber = 4;
Command->ModeRegisterDefinition = 0;
/* Send the command */
HAL_SDRAM_SendCommand(hsdram, Command, 0x1000);
/* Step 7: Program the external memory mode register */
tmpmrd = (uint32_t)SDRAM_MODEREG_BURST_LENGTH_2 |
SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL |
SDRAM_MODEREG_CAS_LATENCY_3 |
SDRAM_MODEREG_OPERATING_MODE_STANDARD |
SDRAM_MODEREG_WRITEBURST_MODE_SINGLE;
Command->CommandMode = FMC_SDRAM_CMD_LOAD_MODE;
Command->CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
Command->AutoRefreshNumber = 1;
Command->ModeRegisterDefinition = tmpmrd;
/* Send the command */
HAL_SDRAM_SendCommand(hsdram, Command, 0x1000);
/* Step 8: Set the refresh rate counter */
/* (15.62 us x Freq) - 20 */
/* Set the device refresh counter */
HAL_SDRAM_ProgramRefreshRate(hsdram, REFRESH_COUNT);
}
The memory and micro are connected according to the schematic
I can use only 8bit of addressing. In this configuration everything is perfect, i.e. I can read/write values and observe them in debug window. It limits me though to only 8MB of memory.
When I modify in settings 8bits up to 9/10/11bits to have more memory available it starts malfunctioning,i.e. garbage in some memory area.
I made customized board, but the same issue you going find on the STM32F429-disco board. So I reject rather the connections. I tried to play with the time delays like "Row to column delay" and increase all delays possible, but not luck. Any help would be appreciated.
From IS42S16400J-7BLI datasheet:
Internally configured as a quad-bank DRAM with a synchronous
interface. Each 16,777,216-bit bank is organized as 4,096 rows by 256
columns by 16 bits.
So, you should use 8 bit in ColumnBitsNumber. And you'll get 8 Mbytes (64 MBits/8) of memory.

Vulkan copying image from swap chain

I am using the vkCmdCopyImageToBuffer function and getting a memory access violation and don't understand why.
Here is the code:
VkBufferImageCopy region = {};
region.bufferOffset = 0;
region.bufferRowLength = width;
region.bufferImageHeight = height;
region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
region.imageSubresource.mipLevel = 0;
region.imageSubresource.baseArrayLayer = 0;
region.imageSubresource.layerCount = 1;
region.imageOffset = { 0, 0, 0 };
region.imageExtent = {
width,
height,
1
};
vkCmdCopyImageToBuffer(m_drawCmdBuffers[i], m_swapChain.buffers[i].image,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, m_renderImage, 1, &region);
The swapchain images are created here in the initialization code:
// Get the swap chain images
images.resize(imageCount);
VK_CHECK_RESULT(fpGetSwapchainImagesKHR(device, swapChain, &imageCount, images.data()));
// Get the swap chain buffers containing the image and imageview
buffers.resize(imageCount);
for (uint32_t i = 0; i < imageCount; i++)
{
VkImageViewCreateInfo colorAttachmentView = {};
colorAttachmentView.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
colorAttachmentView.pNext = NULL;
colorAttachmentView.format = colorFormat;
colorAttachmentView.components = {
VK_COMPONENT_SWIZZLE_R,
VK_COMPONENT_SWIZZLE_G,
VK_COMPONENT_SWIZZLE_B,
VK_COMPONENT_SWIZZLE_A
};
colorAttachmentView.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
colorAttachmentView.subresourceRange.baseMipLevel = 0;
colorAttachmentView.subresourceRange.levelCount = 1;
colorAttachmentView.subresourceRange.baseArrayLayer = 0;
colorAttachmentView.subresourceRange.layerCount = 1;
colorAttachmentView.viewType = VK_IMAGE_VIEW_TYPE_2D;
colorAttachmentView.flags = 0;
buffers[i].image = images[i];
colorAttachmentView.image = buffers[i].image;
VK_CHECK_RESULT(vkCreateImageView(device, &colorAttachmentView, nullptr, &buffers[i].view));
}
And my buffer is similarly created here:
VkBufferCreateInfo createinfo = {};
createinfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
createinfo.size = width * height * 4 * sizeof(int8_t);
createinfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
createinfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
//create the image copy buffer
vkCreateBuffer(m_device, &createinfo, NULL, &m_renderImage);
I have tried different pixel formats and different createinfo.usage settings but none help.
VkSurfaceCapabilitiesKHR::supportedUsageFlags defines the limitations on the ways in which you can use the VkImages created by the swap chain. The only one that is guaranteed to be supported is color attachment; all of the other, including transfer src, are optional.
Therefore, you should not assume that you can copy from a presentable image. If you find yourself with a need to do that, you must first query that value. If it does not allow copies, then you must render to your own image, which you copy from. You can render from that image into the presentable one when you intend to present it.

How to find where does Image Block start in GIF images?

Information source - http://www.onicos.com/staff/iz/formats/gif.html#header
In GIF images the actual image size (width, height) is stored in Image Block. To my best understanding Image Block is the very first block included in header.
Before the actual blocks begin, there is a memory allocation called Global Color Table(0..255 x 3 bytes)(from now-on GCT). If I can know the byte count reserved for GCT I can extract bytes 5-9 from Image Block and have the actual image size.
Question:
How can I know/learn what is the size of the GCT?
OR
Where does GCT end?
OR
Where does Image Block begin?
OR
Where does Image Block end?
All you need for gif enc/dec you will find here 3MF Project GIF
GCT
this block is optional and not always present in a GIF file. Size is determined by number of colors and bit wide from GIF header. I decode/load it like this:
struct _hdr
{
// Header
BYTE Signature[3]; /* Header Signature (always "GIF") */
BYTE Version[3]; /* GIF format version("87a" or "89a") */
// Logical Screen Descriptor
WORD xs;
WORD ys;
BYTE Packed; /* Screen and Color Map Information */
BYTE BackgroundColor; /* Background Color Index */
BYTE AspectRatio; /* Pixel Aspect Ratio */
} hdr;
gcolor_bits= (hdr.Packed &7)+1; // global pallete
scolor_bits=((hdr.Packed>>4)&7)+1; // screen
_gcolor_sorted =hdr.Packed&8;
_gcolor_table =hdr.Packed&128;
scolors=1<<scolor_bits;
gcolors=1<<gcolor_bits;
if _gcolor_table is true then GCT is present
GCT size is 3*gcolors [Bytes] stored in order R,G,B
Start of Image
This one is a bit tricky because GIF89a files may contain many optional blocks. You need to do a decoding loop detecting type of block and decoding/skipping it according its purpose. I do it like this:
struct _gfxext
{
BYTE Introducer; /* Extension Introducer (always 21h) */
BYTE Label; /* Graphic Control Label (always F9h) */
BYTE BlockSize; /* Size of remaining fields (always 04h) */
BYTE Packed; /* Method of graphics disposal to use */
WORD DelayTime; /* Hundredths of seconds to wait */
BYTE ColorIndex; /* Transparent Color Index */
BYTE Terminator; /* Block Terminator (always 0) */
} gfx;
struct _txtext
{
BYTE Introducer; /* Extension Introducer (always 21h) */
BYTE Label; /* Extension Label (always 01h) */
BYTE BlockSize; /* Size of Extension Block (always 0Ch) */
WORD TextGridLeft; /* X position of text grid in pixels */
WORD TextGridTop; /* Y position of text grid in pixels */
WORD TextGridWidth; /* Width of the text grid in pixels */
WORD TextGridHeight; /* Height of the text grid in pixels */
BYTE CellWidth; /* Width of a grid cell in pixels */
BYTE CellHeight; /* Height of a grid cell in pixels */
BYTE TextFgColorIndex; /* Text foreground color index value */
BYTE TextBgColorIndex; /* Text background color index value */
// BYTE *PlainTextData; /* The Plain Text data */
// BYTE Terminator; /* Block Terminator (always 0) */
};
struct _remext
{
BYTE Introducer; /* Extension Introducer (always 21h) */
BYTE Label; /* Comment Label (always FEh) */
// BYTE *CommentData; /* Pointer to Comment Data sub-blocks */
// BYTE Terminator; /* Block Terminator (always 0) */
};
struct _appext
{
BYTE Introducer; /* Extension Introducer (always 21h) */
BYTE Label; /* Extension Label (always FFh) */
BYTE BlockSize; /* Size of Extension Block (always 0Bh) */
CHAR Identifier[8]; /* Application Identifier */
BYTE AuthentCode[3]; /* Application Authentication Code */
// BYTE *ApplicationData; /* Point to Application Data sub-blocks */
// BYTE Terminator; /* Block Terminator (always 0) */
};
// handle 89a extensions blocks
_gfxext gfxext; gfxext.Introducer=0;
_txtext txtext; txtext.Introducer=0;
_remext remext; remext.Introducer=0;
_appext appext; appext.Introducer=0;
if((hdr.Version[0]=='8')
&&(hdr.Version[1]=='9')
&&(hdr.Version[2]=='a')) _89a=true; else _89a=false;
if (_89a)
for (;!f.eof;)
{
f.peek((BYTE*)&dw,2);
if (dw==0xF921) { f.read((BYTE*)&gfxext,sizeof(_gfxext)); }
else if (dw==0x0121) { f.read((BYTE*)&txtext,sizeof(_txtext)); for (;!f.eof;) { f.read(&db,1); if (!db) break; f.read(dat,DWORD(db)); } }
else if (dw==0xFE21) { f.read((BYTE*)&remext,sizeof(_remext)); for (;!f.eof;) { f.read(&db,1); if (!db) break; f.read(dat,DWORD(db)); } }
else if (dw==0xFF21) { f.read((BYTE*)&appext,sizeof(_appext)); for (;!f.eof;) { f.read(&db,1); if (!db) break; f.read(dat,DWORD(db)); } }
else if ((dw&0x00FF)==0x0021) return; // corrupted file
else break; // no extension found
}
db is BYTE variable
dw is WORD variable
f is my file cache class the members are self explanatory I hope anyway:
f.read(&data,size) read size BYTES into data
f.peek(&data,size) do the same but do not update position in file
f.eof indicates end of file reached
this has to be done for each frame after all this image header starts.
End of Image
Image block ends with terminator. All the chunks of image start with BYTE count. If it is zero it is a terminator block. Usually after the image there are few BYTES not used by LZW data so after you fill the whole image area skip all blocks until hit the zero sized block and then stop that is image end. If BYTE after this is 0x3B hex you reached the end of GIF file
[notes]
Do not forget to encapsulate struct by #pragma pack(1) and #pragma pack() or manually set align to 1 BYTE. Beware problems with signed data types (LZW data is unsigned) so overtype where you can to avoid problems or use just unsigned variables (with enough bit-width) for decoding

dsPIC33EV256GM002 PWM settings

I developed a simple program to produce PWM waveform on dsPIC33EV256GM002 but I can't disable it. I used PWM1 and PWM2 and I would generate PWM waveform on PWM1L1 pin (pin 26 on DIP package) maintain PWM1H1 (pin 25 on DIP package) as digital I/O.
Teorically the PWM register setting:
IOCON1bits.PENL = 1; /* PWM1L is controlled by PWM module /
IOCON1bits.PENH = 0; / PWM1H is controlled by GPIO module */
should do that but, using and oscilloscope, I noticed the PWM waveform on PWM1H1 pin, with opposite value (when PWM1L is 1 PWM1H is 0 and veceversa) even if it should be a digital I/O.
Did you find any similar problem ?
Thank you very much for your help and cooperation
regards
I used the following code:
TRISBbits.TRISB10 = 0; /* Set as a digital output */
TRISBbits.TRISB11 = 0; /* Set as a digital output */
TRISBbits.TRISB12 = 0; /* Set as a digital output */
TRISBbits.TRISB13 = 0; /* Set as a digital output */
TRISBbits.TRISB14 = 0; /* Set as a digital output */
TRISBbits.TRISB15 = 0; /* Set as a digital output */
LATBbits.LATB10 = 0; /* Set as a digital output */
LATBbits.LATB11 = 0; /* Set as a digital output */
LATBbits.LATB12 = 0; /* Set as a digital output */
LATBbits.LATB13 = 0; /* Set as a digital output */
LATBbits.LATB14 = 0; /* Set as a digital output */
LATBbits.LATB15 = 0; /* Set as a digital output */
PORTBbits.RB10=0;
PORTBbits.RB11=0;
PORTBbits.RB12=0;
PORTBbits.RB13=0;
PORTBbits.RB14=0;
PORTBbits.RB15=0;
PTPER = 4000;
/*~~~~~~~~~~ PWM1 Configuration ~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
IOCON1bits.PENL = 1; /* PWM1L is controlled by PWM module */
IOCON1bits.PENH = 0; /* PWM1H is controlled by GPIO module */
IOCON1bits.PMOD = 0; /* Select Independent Output PWM mode */
PDC1 = 500; /* Initial Duty cycle */
DTR1 = 0; /* Deadtime setting */
ALTDTR1 = 0; /* Deadtime setting */
PHASE1 = 0; /* No phase shift */
/*~~~~~~~~~~~ PWM2 Configuration ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
IOCON2bits.PENH = 1; /* PWM2H is controlled by PWM module */
IOCON2bits.PENL = 0; /* PWM2L is controlled by GPIO module */
IOCON2bits.PMOD = 0; /* Select Independent Output PWM mode */
PDC2 = 2000; /* Initial Duty cycle */
DTR2 = 0; /* Deadtime setting */
ALTDTR2 = 0; /* Deadtime setting */
PHASE2 = 0; /* */
PTCONbits.PTEN = 1; /* Enable the PWM Module */
The problem was related to the write protection of IOCONxbits register.
I added the following line:
_FDEVOPT( PWMLOCK_OFF );
and this fixed the problem.
I faced same problem with dspic33ev32GP002 and changed configuration bits like so:
// FDEVOPT
#pragma config PWMLOCK = OFF
This worked for me.

Create Email address from names Compiler Design

Creating email addresses form names
You have given a file containing names of several persons. The file will have exactly one name is each line. You need to create email address ending with #bitmesra.ac.in from those names.
the rule for creating email address is defined below: A name will be expressed in the following form:
............
Let F(s) denote the first character of string s.
so, email id will be F(string 1)F(string 2)........._lastString#bitmesra.ac.in
Some names and their corresponding email id's are listed below as an example
Sachin Ramesh Tendulkar s_r_tendulkar#bitmesra.ac.in
Rahul S Dravid r_s_dravid#bitmesra.ac.in
You need to generate a grammer for this.
note: there may multiple spaces b/w names.
My Code is here
#include<cstdio>
#include<cstring>
#include<cctype>
int main()
{
char str1[100],str2[100];
char str3[] = "#bitmesra.ac.in";
while(gets(str1))
{
int index,k=0;
str2[k] = tolower(str1[0]);
for(int i=1;i<strlen(str1);i++)
{
if(str1[i]==' ')
{
index = i;
if(isalpha(str1[i+1]))
{
k++;
str2[k] = '_';
k++;
str2[k] = tolower(str1[i+1]);
}
}
}
index= index + 2;
for(int i=index;str1[i]!='\0';i++)
{
k++;
str2[k] = tolower(str1[i]);
}
str2[++k] = '\0';
strcat(str2,str3);
printf("%s\n",str2);
}
return 0;
}
How to write CFG Grammar For this.....
What about something like:
optnamelist: /* file can be empty */
| namelist /* do nothing */
namelist: nameseq NL /* process vector */
| namelist NL nameseq /* process vector */
nameseq: name /* create vector and add element 1 */
| nameseq name /* add element to vector */
The lexer should take care of white spaces (eat them). The NL token is a sequence of one or more newlines.
If you add names to the end of a vector, you'll have to process it backward.
Your code implies you're writing this in C. So you could use a fixed sized Vector, e.g.
#define MAX_NAMES 100 /* this will probably be enough :-) */
static int actpos;
static char *myVector[MAX_NAMES];
...
/* "create" vector */
memset(myVector, 0, MAX_NAMES * sizeof(char *));
actpos = 0;
...
/* add name to vector */
myVector[actpos] = strdup($1 /* or $2 */);
if (myVector[actpos) == NULL) ... /* out of memory */
actpos++;
if (actpos >= MAX_NAMES) ... /* name too long */
...
/* process vector */
for (i = actpos - 1; i > 0; --i) {
/* add myVector[i][0] to e-mail address */
free(myVector[i]);
}
/* add myVector[0] to e-mail address */
free(myVector[0]);

Resources