VIA 移植 讯飞的TTS 编码与多线程

VIA平台上移植讯飞的TTS,在移植讯飞提供的Sample时,遇到在Syntext死机重启的问题,一直没能解决,后来从VIA公司拿到他们早些年移植后的版本,移到我们的D300中是好用的.

移植过程按说明步骤就好,下面就几点困扰我多时的问题与大家讨论:
一. 编码问题:
如果你对
UNICODE,GBK,UTF-8的区别不是很明白的话,还是读一读这篇文章. UNICODE,GBK,UTF-8区别
,
讯飞的TTS支持近10种的编码,默认的为GBK,但VIA平台上中文默认的为Unicode,英文默认的为ASCII.要想讯飞的TTS与VIA一起能正常工作,就需要统一编码,这里选择的是UTF-8.
提取VIA控件中的文字资源,加上自己定义的文字,合并后用TTS播放:
MenuItemC *item = new MenuItemC();
……
           StringC Name =
item->GetText(); 
           uint32
length=Name.GetLength()/2*3
+3;———-A
           char*
wstrResult=new char[length];
          
memset(wstrResult, 0, length);
          
int32 Chars1 =
Name.ToUtf8Str(wstrResult,length);————–B
           char
words[
3]={0};
          
words[
0]=0xE4;————-C
          
words[
1]=0xB9;
          
words[
2]=0x8B;
          
strcat(wstrResult,words);
 TtsInterSoundTst4(wstrResult);—————D
           delete
[] wstrResult;
———————E    
           wstrResult =
NULL;
就其中的某些部分详细说明一下. [A] Name.GetLength()得到的是控件中文本的长度,Unicode编码的,每个汉字占两个Bytes
(即两个Char),而UTF-8中每个汉字是由三个Bytes组成的,所以要除2乘3得到转换UTF-8后所需要的空间,加3是因为在后面加上了一个UTF-8的汉字占三个Bytes.
[B]是StringC的一个方法,可以输出UTF-8格式的内容,这里就把VIA默认的Unicode转换为了UTF-8.[C]Words[3]
一个UTF-8汉字的空间,[D]调用讯飞的TTS接口进行播放.此时wstrResult应该是UFT-8编码的字节表示,可以用MonPrintf((char*)wstrResult)打印出来查看.
二. 多线程的问题:
如果TtsInterSoundTst4的实现这么来写:
int
TtsInterSoundTst4(char* p)
{
MonPrintf("TtsSynthStartWithPlay!–
strlen(ChsTxtbP) = %d", strlen(ChsTxtbP));
TtsUiCallbackReg(TtsUiCallbackProc,
NULL);
TtsSynthStartWithPlay(p, strlen(p), NULL);—————–
F
return
0;
}
则TTS无法正常播放,起初以为是编码的问题,折腾了许久,后来才发现是多线程与指针的使用有问题,因为TtsSynthStartWithPlay是异步的,所以执行到F这里进,主线程会继续返回,执行E,而F由于优先级较低,所以会稍后执行,但在E的时候,指针指向的空间己被Delete,到TTS来播放时,己经找不到对应的内容了!所以更改了一下,在TtsInterSoundTst4进行了复制,在TTS播放完后,再释放空间.
int
TtsInterSoundTst4(char* p)
{
      content
= (char*) ValMalloc(j+1);
  memset(content, 0, j+1);
   memcpy(content,p,j);
   content[j]=’\0′;
MonPrintf("TtsSynthStartWithPlay!– strlen(content) = %d",
strlen(
content));
TtsUiCallbackReg(TtsUiCallbackProc,
NULL);
TtsSynthStartWithPlay(content, strlen(content), NULL);—————–
F
return
0;
}
至此TTS可以正常播放从VIA控件中获取的Unicode编码的内容,实现读屏.

 

VIA Flash 容量 划分

我们的项目D600,用的是16+8的Flash跟Rom,其中16M的Flash分为约12M的程序区,4M的用户数据区.但在加入大字体(20*20)的后,编译出错,提示:Load region FLASH size
(11557344 bytes) exceeds limit (11272192 bytes).

于是要把用户数据区减少,加大CP区的大小.
要修改两个文件,分别是Hwdflash.c cpflash_16_8.LNK(梅红色的为之前的大小)
Hwdflash.c中

static void
FlashInitSector(HwdFlashLowDevT * devP)

{

 if (devP->man_id ==
HWD_FLASH_MANID_AMD)

  {

#ifdef
FLASH_SPANSIONS71PL127N

    SectorLookupTable =
SectorLookupTable16MTB;

    FlashMaxSector = FLASH_SECTOR_69;

    SectionMapToSector[HWD_FLASH_CP_BOOT_CODE_SECTION].StartSector =
FLASH_SECTOR_0;

    SectionMapToSector[HWD_FLASH_CP_BOOT_CODE_SECTION].EndSector =
FLASH_SECTOR_0;

    SectionMapToSector[HWD_FLASH_CP_CODE_SECTION].StartSector = FLASH_SECTOR_4;

SectionMapToSector[HWD_FLASH_CP_CODE_SECTION].EndSector = FLASH_SECTOR_49;//FLASH_SECTOR_46// 49-4+1=46  A

    SectionMapToSector[HWD_FLASH_DSPM_CODE_SECTION].StartSector =
FlashMaxSector + 1; /*Realy no DSPM and DSPV section */

    SectionMapToSector[HWD_FLASH_DSPM_CODE_SECTION].EndSector =
FlashMaxSector + 1;

    SectionMapToSector[HWD_FLASH_DSPV_CODE_SECTION].StartSector =
FlashMaxSector + 1;

    SectionMapToSector[HWD_FLASH_DSPV_CODE_SECTION].EndSector =
FlashMaxSector + 1;

    SectionMapToSector[HWD_FLASH_CP2_CODE_SECTION].StartSector =
FlashMaxSector + 1;

    SectionMapToSector[HWD_FLASH_CP2_CODE_SECTION].EndSector = FlashMaxSector
+ 1;

    SectionMapToSector[HWD_FLASH_CP3_CODE_SECTION].StartSector =
FlashMaxSector + 1;

    SectionMapToSector[HWD_FLASH_CP3_CODE_SECTION].EndSector = FlashMaxSector
+ 1;

SectionMapToSector[HWD_FLASH_FSM_USER_SECTION].StartSector = FLASH_SECTOR_53;//50

    SectionMapToSector[HWD_FLASH_FSM_USER_SECTION].EndSector = FLASH_SECTOR_65;
    SectionMapToSector[HWD_FLASH_FSM_DATA_SECTION].StartSector = FLASH_SECTOR_1;
    SectionMapToSector[HWD_FLASH_FSM_DATA_SECTION].EndSector = FLASH_SECTOR_3;

    SectionMapToSector[HWD_FLASH_ALL_SECTION].StartSector =
FLASH_SECTOR_0;

    SectionMapToSector[HWD_FLASH_ALL_SECTION].EndSector = FlashMaxSector;

    SectionMapToSector[HWD_FLASH_PRI_SECTION].StartSector = FlashMaxSector +
1;

    SectionMapToSector[HWD_FLASH_PRI_SECTION].EndSector = FlashMaxSector +
1;

    SectionMapToSector[HWD_FLASH_FAULT_DATA_SECTION].StartSector =
FLASH_SECTOR_66;   /*64 k bytes is
ok.*/

    SectionMapToSector[HWD_FLASH_FAULT_DATA_SECTION].EndSector =
FLASH_SECTOR_69;

SectionMapToSector[HWD_FLASH_UI_WALL_PAPPER_SECTION].StartSector = FLASH_SECTOR_50;//47

SectionMapToSector[HWD_FLASH_UI_WALL_PAPPER_SECTION].EndSector = FLASH_SECTOR_50;//47

SectionMapToSector[HWD_FLASH_UI_MAIN_TOPIC_SECTION].StartSector = FLASH_SECTOR_51;//48

SectionMapToSector[HWD_FLASH_UI_MAIN_TOPIC_SECTION].EndSector = FLASH_SECTOR_52;//49

#endif
/*FLASH_SPANSIONS71PL127N */

     }
}

/* Top Bottom type
16M, Spansion S71PL127N, 128 + 64 */

#ifdef
FLASH_SPANSIONS71PL127N

static const uint32
SectorLookupTable16MTB[] = {

  /* 0 – 3 */

  0x00000000, 0x00010000,
0x00020000, 0x00030000, /* 4 blocks of 64K bytes size
= =  FLASH_SECTOR_0 */

  /* 4 – 10 */

  0x00040000, 0x00080000,
0x000C0000, 0x00100000, /* 62 blocks of 256k bytes size
=FLASH_SECTOR_1~4*/

  0x00140000, 0x00180000, 0x001C0000,
  /* 11 – 34 */

  0x00200000, 0x00240000, 0x00280000,
0x002C0000,

  0x00300000, 0x00340000, 0x00380000,
0x003C0000,

  0x00400000, 0x00440000, 0x00480000,
0x004C0000,

  0x00500000, 0x00540000, 0x00580000,
0x005C0000,

  0x00600000, 0x00640000, 0x00680000,
0x006C0000,

  0x00700000, 0x00740000, 0x00780000,
0x007C0000,

  /* 35 – 58 */

  0x00800000, 0x00840000, 0x00880000,
0x008C0000,

  0x00900000, 0x00940000, 0x00980000,
0x009C0000,

  0x00A00000, 0x00A40000,
0x00A80000, 0x00AC0000,

/
* FLASH_SECTOR_43 */A+2=48 == 0x00B40000

  0x00B00000, 0x00B40000, 0x00B80000, 0x00BC0000,

  0x00C00000, 0x00C40000, 0x00C80000,
0x00CC0000,

  0x00D00000, 0x00D40000, 0x00D80000,
0x00DC0000,

  /* 59 – 65 */

  0x00E00000, 0x00E40000, 0x00E80000,
0x00EC0000,

  0x00F00000, 0x00F40000, 0x00F80000,
  /* 66 – 69 */

  0x00FC0000, 0x00FD0000, 0x00FE0000,
0x00FF0000, /* 4 blocks of 64K bytes size */

  0x01000000, 0x01000000
};

#endif
/*FLASH_SPANSIONS71PL127N */

cpflash_16_8.LNK文件中:

FLASH  0x00040000 0x00B80000 // 0x00AC0000
{
   FLASH 0x00040000 0x00B40000
   {
      copy.o     (+RO, +FIRST)
      *          (+RO)
   }
}

Hwdflash.c 中貌似可以根据需要任意调整FLASH_SECTOR的大小(不要超过最大值),关键的是LNK文件中数值大小的确定:方法为

FLASH_SECTOR_49FLASH_SECTOR_4+1=46; (1是因为包含此分块) 所以在SectorLookupTable16MTB表中查找到第46块,然后再加2(因为0 – 3 对应了FLASH_SECTOR_1 ,4开始对应FLASH_SECTOR_2所以46对应了第48组数,即为0x00B40000,又因为LNK文件中的第二个数是大小,而非终止位置,所以要填第49组数0x00B80000)
以上只是以UI的观点来看驱动调整,不对之处还请指证:)

 

VIA Selle平台 Singleton单件模式

"单件模式的使用意图就是:保证一个类仅有一个实例,并提供一个该实例全局的访问点",在VIA的应用层中,各种应用都是基于类来实现的,例如Call,SMS,Alarm等等,运行其间仅需要一个实例来进行操作(多实例会耗费更多的资源,引起管理上的麻烦,没有必要)

这里以Alarm为例来说明VIA的Singleton单件模式的实现:
class AlarmAppC : public
ApplicationC
{
public: 
 virtual
~AlarmAppC(void);
 static AlarmAppC*
GetInstance();
     ……
private:   
 static AlarmAppC*
_instance;
AlarmAppC(void);
}
AlarmAppC
*AlarmAppC::_instance = NULL;
AlarmAppC*
AlarmAppC::GetInstance()
{
 if (_instance ==
NULL)
 {
    _instance = new
AlarmAppC();
 }
 return _instance;
}
"私有化构造函数,使类的使用者调用不到这个构造函数来new一个实例。类型中可以自己new一个实例。类中创建一个静态私有变量和Static公有属性。在公有属性中实现此类的实例化。这样在第一次请求时创建此对象."
单件模式实际上是利用控制对象创造过程来控制对象的创造个数的方法,这样在Selle运行的过程中,就只有一个Alarm的实例,并且可以在APP层随意调用此Alarm来进行判断或处理.
参考资料:
       <<GoF+23种设计模式解析>>