diaowinner 发表于 2020-2-26 22:49:49

卡西欧Prizm计算器如何编程?

本帖最后由 diaowinner 于 2020-3-14 16:35 编辑

转载自Cemetech的WikiPrizm,侵权删除!众所周知,卡西欧只有fx-9860G系列有SDK,所以如何在Prizm(其实就是fx-CG系列)计算器编程呢?
这时候就需要一款软件来帮忙——他就是PrizmSDK!
首先下载这个SDK,然后拖一下就能用了~简单吧~
将压缩文件夹解压缩到计算机上的任何位置,例如“我的文档”文件夹。 尽管您需要压缩档案中的每个目录来构建Prizm的加载项,但是您将主要在projects/文件夹中工作。 首先,将projects/default/文件夹复制为projects/yourproject,将您的项目更改为项目的名称。 您需要确保有一个包含如下内容的make.bat文件:..\..\bin\make.exe %*
pause接下来,再次使用项目的实际名称将default.c重命名为yourproject.c(应为全字母,数字和带下划线的空格)。 最后,根据您的喜好编辑Makefile。 它应包含以下内容:...
CSOURCES=yourproject.c
...
BIN=yourproject.bin如果您希望使用位图图标,则在Makefile中还需要类似这样的内容我才不会告诉你原文没有冒号的呢MKG3AFLAGS=-i uns:yourproject_u.bmp -i sel:yourproject_s.bmp -n basic:YourProject在这里,yourproject_u.bmp是未选择的图标图像,yourproject_s.bmp是已选择的图标,而YourProject是要显示的加载项的名称。 有关创建外接程序图标的更多信息,请参见这个网格:
https://img.ourl.ca/prizmguidelines.png。
准备好构建项目时,只需双击make.bat文件。 它将暂停,以便您可以检查任何错误或警告,然后关闭。所以我才不会告诉你是谷歌翻译这个来的
啥?Linux用户?我相信你会英文的。以下内容未完成本教程将向您介绍Prizm SDK(0.3版),其结构以及创建和构建项目的方式。
“包含文件夹”包含C / C ++程序的必需标头。 已知标头有点混乱,并且标头的重建正在完成。
“公用文件夹”是prizm.ld和prizm_rules这两个文件的宿主。 prizm.ld是链接器在编译时使用的文件,以提供有关prizm,数据和ram的布局方式以及放置内容的信息。 prizm_rules是一个Makefile,包含在项目文件夹中的Makefile中。 该文件定义通用设置,并且是构建所需的文件。
设置“项目文件夹”是为了简化存储和构建Prizm项目。
每个子项目中使用的Makefile是预先制作的,几乎不需要修改。 该文件的目的仅仅是在src /下构建所有源文件并制作一个.g3a。
mkg3a是一个实用程序,用于将二进制文件以及所选和取消选择的图标转换为.g3a,可在Prizm上执行。
以上内容未完成你好,世界!创建项目:使用PrizmSDK创建项目的最简单方法是复制现有项目目录。 如果这确实是您使用PrizmSDK的第一个项目,那么您应该在projects文件夹中已经有一个名为“example”的项目文件夹。 复制此文件夹并将其命名为简单名称(例如tut1)。
此文件夹包含您插件的所有源代码,资源和构建系统。 在开始项目之前,您需要做的第一件事就是设置构建系统。 打开Makefile文件。 您将看到它已经设置为编译src文件夹中的所有源并创建一个插件。 查找以以下内容开头的行:MKG3AFLAGS := ...当您开始一个新项目时,这一行很重要。 这行代码决定了您的插件的名称及其使用的图标(稍后将进行介绍)。 请参阅mkg3a用法部分以获取有关参数说明的信息。 现在,您需要修改插件的名称。 更改-n basic:example并使用您的插件名称更改示例。
测试大楼:现在,您已经建立了构建系统。 为了进行测试,我们需要向您的src文件夹中添加一些代码。 首先,删除src文件夹中已经存在的所有文件,然后创建一个新的.c或.cpp文件。 我将名称main.cpp用于源文件。 打开源文件,并将以下文件放入其中:int main()
{
return 0;
}这不会做任何事情,也不应该在Prizm上运行,但是我们需要一些东西来测试您的插件的构建。 在终端(Unix)或cmd.exe(Windows)中,将cd插入项目文件夹并运行make。 例如,如果您的项目名为tut1,则可以$ cd /projects/tut1
$ make兄啊这是Unix啊所以Windows用户应修改以上命令
如果一切顺利,则您应该没有构建错误,并且在tut1文件夹中将有一个.g3a。 如果有问题,最好发布在Cemetech Prizm子论坛。 这基本上是产生.g3a的方法。
制作您的第一个插件:现在,您已经设置了项目文件夹,您可以学习有关如何编码插件的知识。 首先,在尝试编码之前,您应该了解某些事情:
[*]Prizm没有内置的libc或libstdc ++。这意味着您无法在其他平台上进行编程时使用可用的功能,例如printf,文件IO,std名称空间等。编辑:PrizmSDK 0.4将具有这些功能!
[*]Prizm有自己的功能,尚未完全记录。 这意味着您必须阅读其他插件的源代码,查找社区文档或使用此Wiki。 请帮助我们继续扩展此Wiki!
[*]主函数不应返回。 插件无法自行关闭,您必须让操作系统通过用户键输入将其关闭。 如果您确实在main函数内部返回,则您的插件将无法再次恢复,直到操作系统关闭它为止。
[*]标头仍在重组中,功能可能丢失或出现在奇数标头中。 (见下文)
[*]当前的PrizmSDK(0.3)已过时,并且具有错误的功能和标题。 最好的选择是直接从github获取libfxcg。
现在,让我们开始添加代码以在屏幕上打印Hello World。#include <fxcg/display.h>
#include <fxcg/keyboard.h>如上所述,标头有点散开。 这些标头包含一些重要功能,例如PrintXY和GetKey。 现在,我们可以从添加一个正常的main函数开始int main() {
return 0; // Needed if you have main returning int, but will never be reached.
}现在,如果您阅读PrintXY的文档,将会看到可以打印出字母坐标中的彩色文本。 您还应该注意,字符串必须以2个垃圾字母开头。 认为该字符串以实际的16位数字开头,然后是该字符串。 另外,出乎意料的是,X和Y从1开始,而不是0。我们可以在您的主函数中添加一个简单的示例,例如PrintXY(3,8,"--Hello World!", TEXT_MODE_NORMAL, TEXT_COLOR_RED); //将其放在屏幕上的某个位置TEXT_ *在color.h中定义。 您可以在标题中查看您的选项。
现在,由于运行此代码将在打印文本后返回收益,因此我们需要一种更好的方式来运行插件。 GeyKey功能将等待按键被按下并处理键,因此用户可以退出您的插件。 这是由操作系统完成的,外接程序不知道键。 让我们添加代码以永久读取密钥,以便用户可以退出您的插件:int key;
while(1)
GetKey(&key); // Loop forever这是运行您的插件所需的所有代码! 您可以构建并运行您的插件。当然还可以用下文的代码:#include <fxcg/display.h>
#include <fxcg/keyboard.h>

int main() {
PrintXY(3,8,"--Hello World!", TEXT_MODE_NORMAL, TEXT_COLOR_RED); //将其放在屏幕上的某个位置。 请注意,x,y是1索引的。

int key;
while(1)
    GetKey(&key); //永远循环

return 0; //如果您有主返回int,则需要它,但永远不会达到。
}然后把它拖到你的计算器根目录里,完事~( ̄▽ ̄)~*
在Prizm的屏幕上打印文本并不容易且简单。 本教程将向您展示将信息打印到屏幕上的方式(已知方式)。
打印字符串:如上一页所见,PrintXY用于将文本打印到LCD。 这只是在Prizm上打印文本的一种方法。 我将介绍以下不同的方法来打印文本。
[*]PrintXY:PrintXY是将文本打印到屏幕上特定位置的常用方法。 请注意,它会忽略string参数的前两个字节,因此您通常希望用任意两个字符填充字符串的开头,或者从字符串的地址中减去两个字符(请注意PrintXY页上讨论的警告)。
PrintXY提供了两种自定义打印文本的方式,即int display_mode和int text_color。 显示模式为0会将显示设置为带有白色背景的打印文本。 1将反转文本,将前景(text_color)与背景(白色)颜色翻转。 0x20会将文本或显示在屏幕上(背景色是透明的)。 如果你这样做PrintXY(1,1,"Hello",0,TEXT_COLOR_RED);
PrintXY(1,1,"World",0x20,TEXT_COLOR_BLUE);您会在单词“ Hello”上方看到单词“ World”。 最后,您可以将0x21作为显示模式。 这将用作与屏幕的“与”字。 如果两个像素(将要绘制的内容和已绘制的内容)均处于“打开”状态,或具有除白色以外的其他颜色,则屏幕上的像素不变。 否则,屏幕上的像素将变为白色。 您可以自己进行测试PrintXY(1,1,"Hello",0,0);
PrintXY(1,1,"World",0x21,TEXT_COLOR_RED);您已经看到我在使用PrintXY时使用颜色。 您可以在PrizmSDK的include文件夹中的color.h文件中获取所有颜色的列表。 请注意,您只能使用TEXT_COLOR_ *。
[*]Print_OS和locate_OS:Print_OS通过打印从文本光标开始的文本来工作。 可以使用locate_OS设置文本光标。 这是一个例子:locate_OS(1,1);
Print_OS("Hello ",0,0);
Print_OS("World!",0,0);您会注意到文本一起出现。 这是因为Print_OS在打印时会移动文本光标。
该命令可以更改模式,就像PrintXY一样,但是不能更改颜色。
[*]显示小字体:Prizm不仅可以让您打印8行巨型字母,还可以让您使用PrintMini以Mini字体打印。 此功能稍微复杂一点,但有其优点。 这是如何以迷你字体打印的示例:int x = 0; // This function uses pixels
int y = 0;PrintMini(&x, &y, "abcdEFGH1234!@#$.,;'", 0, 0xffffffff, 0,0,COLOR_DARKGREEN, COLOR_GRAY, 1,0);如您所见,此函数使用指针。 这是因为PrintMini会将位置更新为最后一个打印字符之后的位置。 颜色参数是16位RGB565,而不是其他文本函数中使用的TEXT_COLOR_ *值。 一些参数的用途未知,应保留在此处。
此函数的前两个参数必须是有效的指针。 初学者经常尝试强制此函数将强制转换为指针的文字值,这将导致崩溃。//错误!
PrintMini(0, 0, ...);
//也是错误,但是编译器不会提醒
PrintMini((int*)0, (int*)0, ...);
//正确
int x, y;
PrintMini(&x, &y, ...)启用建议的编译器警告后,此处第一个示例的常见错误将在编译时导致警告。 第二个命令显式地使这些警告静音,并且这样做是错误的,例如初学者可能会使编译器警告静音。
[*]显示超小字体:注意!libfxcg中尚不存在此功能! 如果您喜欢Mini字体,因为它很小,那么您应该知道还有一个甚至更小的10像素高字体。 可以使用PrintMiniMini进行绘制。 它是参数的PrintMini和PrintXY的混合。 这是一个示例: int x = 0;
int y = 0;
PrintMiniMini(&x, &y, "abcdEFGH1234!@#$.,;'", 0b00010000, TEXT_COLOR_CYAN, 0);

x = 0;
y = 12;
PrintMiniMini(&x, &y, "abcdEFGH1234!@#$.,;'", 0, TEXT_COLOR_CYAN, 0);像上面的警告一样,必须用指向int值的指针!不然怎么样你懂得
您可能想知道为什么我要执行两次。 这只是为了展示一个事实,即MiniMini字体可以在相同高度处设置为粗体。 您应该熟悉位置指针和字符串。 与PrintMini不同,此功能使用3位颜色。
数字训练:对于调试,对评分游戏等非常有用的一件事就是能够打印出数字。 您可以使用itoa将数字转换为文本。 请注意,itoa位于CONVERT_syscalls.h标头中。 这是打印数字的示例:#include <display.h>
#include <keyboard.h>
#include <CONVERT_syscalls.h>

int main()
{
int number = 12345;
//该缓冲区必须足够大以容纳32位带符号的数字。
//12来自ceil(log10(1 << 30)),再加上一个字节的符号
//一个空终止符。
unsigned char buffer;

itoa(number, buffer);
locate_OS(1,1);
Print_OS(buffer,0,0);

int key;
while(1) GetKey(&key);
}本示例使用Print_OS,因为Print_OS不需要2个垃圾字符。 本示例还使用无符号char*缓冲区,而不是char*缓冲区。 要改为使用PrintXY,可以使用以下命令:char buffer;
itoa(number,(unsigned char*)buffer + 2); //留下垃圾字节
PrintXY(1,1,buffer,0,TEXT_COLOR_BLUE);PrintMini和PrintMiniMini的注意事项:指向PrintMini的指针参数的用途可能并不明显,但是当您希望基于打印的文本的大小执行计算时,它很有用。 例如:int x = 0;
int y = CELL_Y;
PrintMiniMini(&x, &y, "December", 0, TEXT_COLOR_CYAN, 1);
x = CELL_X + (CELL_WIDTH - x)/2;
PrintMiniMini(&x, &y, "December", 0, TEXT_COLOR_CYAN, 0);这段代码到底应该做什么? 该示例用于绘制居中对齐的文本“December”,位于位于CELL_X,CELL_Y的单元格中。int x = 0;
int y = CELL_Y;X值设置为0,因为该加载项需要找到文本“December”的宽度。 Y值设置为我们的目标CELL_Y,因为它不会改变。PrintMiniMini(&x, &y, "December", 0, TEXT_COLOR_CYAN, 1);该函数通常会在(x,y)处打印出文本,但最后一个参数是1。这将导致该函数仅更改X和Y值,但不会绘制。x = CELL_X + (CELL_WIDTH - x)/2;
PrintMiniMini(&x, &y, "December", 0, TEXT_COLOR_CYAN, 0);在此,为X值分配校正后的值。 (鉴于CELL_WIDTH是绘制文本所在的单元格的宽度)。 再次调用PrintMiniMini函数,最后一个参数为0,因此它现在绘制单元格中居中对齐的文本。
以下内容未完成从用户那里获取输入信息将使外接程序不仅有用,而且对于正确的外接程序功能也是必需的。 有许多功能可以读取输入,每个功能都有其优点和缺点。
GetKey:GetKey是读取键输入的非常基本的方法。 该功能处于阻止状态(停止执行,直到用户按下不是的键为止)。 它还处理键。
PRGM_GetKey:这是社区制作的函数,该函数调用PRGM_GetKey_OS并取消对PRGM_GetKey_OS返回的键值进行解密。 注意:PRGM_GetKey函数不属于PrizmSDK。 您可以在PRGM_GetKey页面上获得函数的源代码。
此功能对游戏非常有用,因为该功能不会阻塞并且返回的值易于理解。 (修复程序:这是否检查MENU?添加有关该值及其与键盘的关系的文本。)
GetKeyWait_OS:
直接读取键盘硬件:
字符串输入——简单:在某些情况下,您将需要从用户那里获取一些文本输入。 如果它甚至无法获得文本输入,那么该操作系统将真是愚蠢。 输入的最简单形式是字符串输入。 使用字符串输入,您可以获取任何文本输入,而不必过滤或替换键。 为此,您必须使用两个系统调用DisplayMBString和EditMBStringCtrl。 第一个系统调用使用给定的设置绘制字符串缓冲区,并将光标放置在正确的位置。 EditMBStringCtrl将进行任何按键处理并为您处理。 这使您可以使用最少的编码来实现标准化的输入法。
首先,您必须设置适当的变量,这些变量用于存储输入法的值和数据。char *buffer = (char*)malloc(256); //一些字符串长度
int start = 0; //用于左右滚动
int cursor = 0; //光标位置
buffer = '\0'; //这会将第一个字符设置为\0,也用空字符串“”表示这就是您所需的全部设置! 现在,我们只需要在获取密钥之前绘制字符串DisplayMBString((unsigned char*)buffer, start, cursor, 1, 1); //最后一个参数是X,Y坐标(不以像素为单位)此调用绘制字符串。 它将绘制字符,直到它到达屏幕的右侧。 请注意,这是调用此syscall的唯一时间。 这是因为下一个要调用的系统调用将是GetKey,这是一个阻塞的系统调用。 如果省略此呼叫,则在您按一个键之前,屏幕上将不会绘制任何内容。
现在绘制完成了,可以进行事件循环了!int key;
while(1)
{
GetKey(&key); //阻止是好的。 这将处理标准密钥,并可能在等待时关闭CPU的电源

if(key == KEY_CTRL_EXE || key == KEY_CTRL_EXIT)
    break;

//加上
}现在,如您所见,这只是轮询键并在按下EXIT或EXE时中断-您可以根据需要进行更改,但这是操作系统的标准过程。 如果要检查用户是否按了EXE,只需在while循环后查看key == KEY_CTRL_EXE,还是在while循环中处理键检查。
接下来,我们需要添加处理所有按键的魔术代码。 用以下代码替换//要添加注释:if(key && key < 30000)
{
cursor = EditMBStringChar((unsigned char*)buffer, 256, cursor, key);
DisplayMBString((unsigned char*)buffer, start, cursor, 1,1);
}
else
{
EditMBStringCtrl((unsigned char*)buffer, 256, &start, &cursor, &key, 1, 1);
}等等,仅此而已? 确实。 由于使用了高级GetKey syscall,因此可以让OS处理字符串的编辑并更改缓冲区,光标和滚动! 首先,您需要一个if语句,因为操作系统将ctrl和char键处理分开。 控制键起始于30000,因此您必须单独处理它们。 在这里,我们只是根据类型将键值传递给正确的函数。
最终代码如下:char *buffer = malloc(256); // Some string length
int start = 0; // Used for scrolling left and right
int cursor = 0; // Cursor position

buffer = '\0'; // This sets the first character to \0, also represented by "", an empty string

DisplayMBString((unsigned char*)buffer, start, cursor, 1, 1); // Last to parameters are X,Y coords (not in pixels)

int key;
while(1)
{
GetKey(&key); // Blocking is GOOD.This gets standard keys processed and, possibly, powers down the CPU while waiting

if(key == KEY_CTRL_EXE)
{
    // Ok
    break;
}
else if(key == KEY_CTRL_EXIT)
{
    // Aborted
    break;
}

if(key && key < 30000)
{
    cursor = EditMBStringChar((unsigned char*)buffer, 256, cursor, key);
    DisplayMBString((unsigned char*)buffer, start, cursor, 1,1);
}
else
{
    EditMBStringCtrl((unsigned char*)buffer, 256, &start, &cursor, &key, 1, 1);
}
}这可能属于其他地方,但无论如何都应注意。
对于设置项0x14,以下标志表示:
0x01:移位
0x02:剪辑
0x04:Alpha(未锁定)
0x08:小写字母Alpha(未锁定)
0x84:Alpha锁定
0x88:小写字母锁定
以上内容未完成
以下内容未完成在某些时候,您将需要在外接程序关闭后保存数据。 运行矩阵保存变量,eActivity保存您的文档等。保存文件与fopen(...)不同,您必须了解Prizm上的两个文件系统以及何时使用每个文件系统。
关于文件系统:Prizm包含两个文件系统,主内存(基于RAM)和存储内存(基于ROM)。 当您将Prizm连接到PC时,您会注意到列出了Main Memory文件夹。 这将允许您访问主存储器。
[*]主存储器:主存储器用于快速存储临时数据。 这包括变量,窗口设置,统计数据和系统首选项。 RAM可以快速读取和写入,因此非常适合在外接程序运行时保存更改。 缺点是主内存很小。 它只有61KB的大小,如果Prizm断电时间足够长,可以将其删除。 其他限制包括:不允许子文件夹。 仅位于主存储器根目录中的文件夹;不允许使用长文件名;所有文件都存储为.g3m文件;读取/写入数据的功能与在PC上写入文件的方式非常不同。 您一次读取/写入整个文件,而不是存储存储器;USB对主存储器的访问受到限制
[*]存储内存:存储内存是一个16MB的区域,用于存储大型文件或掉电后所需的文件。 文件系统确实有限制。 在创建另一个文件之前,您必须知道文件的大小。 如果未关闭未知大小的文件,可以这样做以防止损坏。 另一个缺点是写入ROM的速度非常慢。 优点是您一次只能读写一点,而不是一次全部读写。有关Prizm中闪存芯片的技术规格,请参阅闪存文章。

与文件系统交互:
[*]主存储器:主存储器使用MCS功能。 这些功能使用状态系统来跟踪您正在访问的文件。 您必须选择要使用的文件,然后调用函数对其进行操作,这与使用指针一次访问多文件的存储存储器不同。
[*]开启档案:要打开文件进行读取,必须使用MCSGetDlen2。 请记住,主存储器不能包含子文件夹,因此,未签名的char * dir是文件夹名称或为空。 int * data_len是一个指向文件长度存储位置的指针。 如果文件不存在,请执行。 如果是这样,则将大小存储在int中。 这是一个例子:MCSGetDlen2((unsigned char*)"test", (unsigned char*)"test", &x);
[*]写文件:要将数据写入文件,可以选择替换文件或仅更改文件的一部分。 MCSOvwDat2会将数据添加到文件中的指定位置,如果尚不存在,则会创建数据。 这是一个用法示例:汉化员皮一下如果要使用给定的数据制作新文件,则可以使用MCSPutVar2。 请注意,如果文件存在,则会返回错误代码,并且不会写入数据。 这是一个用法示例:MCSPutVar2((unsigned char*)"test", (unsigned char*)"test", strlen("Hello World")+1, (void*)"Hello World");
[*]读取文件:要从文件读取数据,可以使用MCSGetData1。 为了使用此功能,必须先将文件标记为“活动”。 您可以通过调用MCSGetDlen2来实现。 这是读取数据的示例:unsigned char *buffer;
int size;

if(MCSGetDlen2((unsigned char*)"test", (unsigned char*)"test", &size) == 0) //仅在成功时
{
buffer = (unsigned char*)malloc(size);
MCSGetData1(0,size,(void*)buffer);
//做点什么
free(buffer);
}
[*]创建和删除文件夹:您已经看到了使用的文件夹名称,因此至少应该知道如何管理文件夹。 MCS_CreateDirectory用于创建文件夹。 这是一个示例:要删除文件夹,可以使用MCS_DeleteDirectory。
记住要始终检查返回值,以防检测到错误,例如尝试在不存在的文件夹中写入文件或读取不存在的文件。 我在下面的部分中包含了一些错误代码。
请注意,文件夹可能已创建并且不可见。 这是因为加载项只会看到其中包含数据的文件夹。
[*]例子:让我们以上面的内容为例,简要说明一下如何使用主内存。 #include <display.h>
#include <color.h>
#include <keyboard.h>
#include <MCS_syscalls.h>
#include <CONVERT_syscalls.h>
#include <STD_syscalls.h>
#define TEST_STR "Hello World"

int main()
{
   int x;
   unsigned char buffer;
   
   locate_OS(1,1);
   Print_OS((unsigned char*)"Making folder:",0,0);
   itoa(MCS_CreateDirectory((unsigned char*)"test"),buffer);
   Print_OS(buffer,0,0);
   
   locate_OS(1,2);
   Print_OS((unsigned char*)"Making folder:",0,0);
   itoa(MCS_CreateDirectory((unsigned char*)"test"),buffer);
   Print_OS(buffer,0,0);
   
   locate_OS(1,3);
   Print_OS((unsigned char*)"Writing:",0,0);
   itoa(MCSPutVar2((unsigned char*)"test", (unsigned char*)"test", strlen(TEST_STR)+1, (void*)TEST_STR), buffer);
   Print_OS(buffer,0,0);
   
   locate_OS(1,4);
   Print_OS((unsigned char*)"Opening:",0,0);
   itoa(MCSGetDlen2((unsigned char*)"test", (unsigned char*)"test", &x), buffer);
   Print_OS(buffer, 0,0);
   
   locate_OS(1,5);
   Print_OS((unsigned char*)"Reading:",0,0);
   MCSGetData1(0, (x > 20 ? 20 : x), buffer);
   Print_OS(buffer,0,0);
   
   locate_OS(1,6);
   Print_OS((unsigned char*)"Deleting folder:", 0,0);
   itoa(MCS_DeleteDirectory((unsigned char*)"test"), buffer);
   Print_OS(buffer,0,0);
   
   int key;
   while(1) GetKey(&key);
}这是第一次在Prizm上运行时插件的输出:Making folder:0
Making folder:64
Writing:0
Opening:0
Reading:Hello World
Deleting folder:69
我使程序离开了文件和文件夹。如果再次运行它,将会看到更多错误报告:Making folder:64
Making folder:64
Writing:37
Opening:0
Reading:Hello World
Deleting folder:69
如果您需要更多信息,请确保访问“ MCS功能”页面。
[*]错误代码:64-目录已存在(MCS_CreateDirectory)
69-目录不为空(MCS_DeleteDirectory)
37-文件已存在(MCSPutVar2)
储存记忆体:与主存储器不同,存储存储器是Prizm的长期存储。 存储内存使用Bfile syscall,就像主内存使用MCS函数一样。 请记住,即使有很多可用的存储空间,也请尝试使用主内存。 即使仅使文档供calc使用,主存储器仍然是一个选项(基本程序,电子表格等存储在主存储器中)。
[*]制作文件和文件夹:从存储内存开始时,您应该意识到它不像fopen(“ / some / path / test.txt”,“ w”);那样容易。 Prizm对文件系统的使用非常严格。在打开文件进行写入之前,必须确保首先存在该文件。 (您可以通过尝试打开它来完成此操作,但是我将在本教程的后面部分中进行操作)。如果该文件不存在,则必须手动创建它。 Bfile_CreateEntry_OS将创建一个空白条目(注释条目,而不是文件)。如果查看它的参数,您会注意到它需要一个文件名(当然),但是它也需要一个模式和一个大小。这些特定于Prizm。
该模式指定条目是文件还是文件夹。这结合了文件/文件夹的创建和删除。由于我们需要一个文件,因此我们也需要一个大小。文件的大小是静态的。创建文件后,无法调整其大小,除非您制作另一个具有新大小的文件并复制数据。现在您已经知道了模式和大小,我需要触摸文件名。它不仅是一个简单的字符串,而且是一个16位字符串。即使GCC可以生成16位字符串并可以在Prizm上运行,但它们也不完全相同。要将字符串转换为Prizm的字符串格式,必须使用Bfile_StrToName_ncpy(和Bfile_NameToStr_ncpy可以进行其他操作,但现在不需要)。
Bfile_StrToName_ncpy将字符数组转换为n * 2字节的缓冲区。这是用法示例:#define PATH "\\\\fls0\\file.txt"
unsigned short buffer;

Bfile_StrToName_ncpy(buffer, (unsigned char*)PATH, sizeof(PATH));您可以看到输出缓冲区的大小必须是原始字符串的两倍。 您还将注意到路径以\\ fls0 \开头(在C源代码中转义为\\\\ fls0 \\)。 这是因为操作系统基于以前的带有SD卡的计算器,可以使用\\ crd0 \访问。 现在有了文件名,我们终于可以创建一个文件夹和文件了。 这是创建两者的示例:#define CREATEMODE_FILE 1
#define CREATEMODE_FOLDER 5
//这些不在PrizmSDK中,但更容易记住。
#define FOLDER_PATH "\\\\fls0\\Example"
#define FILE_PATH "\\\\fls0\\Example\\File.txt"

unsigned short pFolder, pFile; //创建缓冲区
int size = 128; // 128 byte file

Bfile_StrToName_ncpy(pFolder, (unsigned char*)FOLDER_PATH, sizeof(FOLDER_PATH)); //复制
Bfile_StrToName_ncpy(pFile, (unsigned char*)FILE_PATH, sizeof(FILE_PATH));

Bfile_CreateEntry_OS(pFolder, CREATEMODE_FOLDER, 0);
Bfile_CreateEntry_OS(pFile, CREATEMODE_FILE, &size);
[*]删除文件和文件夹:如果运行此代码,您将看到它在其中创建了文件夹和文件(可以在PC上或从calc的“内存管理器”中查看)。 如果检查size的值,则将注意到此示例它会更改。 您必须使用它给您的价值,而不是您打算成为的价值。 现在,创建的反义是删除,与创建非常相似。 Bfile_DeleteEntry用于删除条目。 它只有一个文件名参数(也需要为16位),但不询问模式。 这是因为它会自动检测您要删除的内容。 这是有关删除的示例:#define CREATEMODE_FILE 1
#define CREATEMODE_FOLDER 5
//这些不在PrizmSDK中,但更容易记住。
#define FOLDER_PATH "\\\\fls0\\Example"
#define FILE_PATH "\\\\fls0\\Example\\File.txt"

unsigned short pFolder, pFile; //创建缓冲区

Bfile_StrToName_ncpy(pFolder, (unsigned char*)FOLDER_PATH, sizeof(FOLDER_PATH));
Bfile_StrToName_ncpy(pFile, (unsigned char*)FILE_PATH, sizeof(FILE_PATH));

Bfile_DeleteEntry(pFolder, CREATEMODE_FOLDER, 0); //删除文件夹会删除内容-小心
[*]开启档案:现在您已经知道如何制作和删除文件和文件夹,接下来继续使用Bfile_OpenFile_OS打开文件。 这需要一个16位的文件名和一个模式。 功能页上说明了该模式。 现在,此函数在打开时返回文件的句柄,如果失败则返回负数。 这是一种检测文件是否存在的方法。 另一种方法是使用Bfile_FindFirst和friend,稍后会涉及到。 这是有关如何正确打开文件,并根据需要创建文件的示例:#define CREATEMODE_FILE 1
#define CREATEMODE_FOLDER 5
#define READ 0
#define READ_SHARE 1
#define WRITE 2
#define READWRITE 3
#define READWRITE_SHARE 4
//这些不在PrizmSDK中,但更容易记住。
#define FILE_PATH "\\\\fls0\\File.txt"

unsigned short pFile; //创建缓冲区
int hFile;

Bfile_StrToName_ncpy(pFile, (unsigned char*)FILE_PATH, sizeof(FILE_PATH));
hFile = Bfile_OpenFile_OS(pFile, READWRITE); //获取句柄

if(hFile < 0) //检查是否打开
{
int size = 256;
if(Bfile_CreateEntry_OS(pFile, CREATEMODE_FILE, &size) >= 0) //它创建了吗?
{
    hFile = Bfile_OpenFile_OS(pFile, READWRITE);
    if(hFile < 0) //还是失败?
    {
      //死于致命错误
      //这不应该发生
    }
}
else
{
    //死于致命错误
    //这不应该发生
}
}
[*]写入文件:现在您已经打开了文件句柄,您可以读取和/或写入文件了。 请记住,文件具有静态大小,无法扩展。 编写时,必须使用Bfile_WriteFile_OS。 这个功能很容易理解。 使用Bfile_OpenFile_OS返回的句柄,可以将数据写入文件中的当前位置,例如:#define STR "Hello World!"
//从之前开始使用hFile
Bfile_WriteFile_OS(hFile, STR, sizeof(STR));
[*]寻求与讲述:注意:最新的libfxcg具有这两个功能,并且正在运行。
现在,在继续阅读等内容之前,让我先触摸一下Bfile_SeekFile_OS和Bfile_TellFile_OS,因为可以在此处轻松显示其用法。 仍然记住文件大小是静态的,您可以在文件中的任何位置(绝对位置)搜索并写入数据。 这是一个基于以上示例的示例:#define STR "Hello People"
//从之前开始使用hFile
Bfile_WriteFile_OS(hFile, STR, sizeof(STR));

//现在,搜索该可怕的字符串并将其更改为更好的名称(笑)
Bfile_SeekFile_OS(hFile, 6); //由|表示的位置:“你好|人”
Bfile_WriteFile_OS(hFile, "World!", 7); //现在文件是“ Hello World!”
int position = Bfile_TellFile_OS(hFile); //为我们提供位置13。
[*]读取文件:恭喜,您知道如何打开文件并在其中的任何位置写入。现在,让我们开始使用Bfile_ReadFile_OS读取文件。此函数不像Bfile_WriteFile_OS那样简单,因为我们可以通过两种方式移动文件中的位置。您会注意到一个新的参数int readpos。通常,如果您需要阅读其他地方的内容,则只会寻求新的职位。由于某些原因,Prizm允许您在同一功能中更改位置。假设您需要在位置10读取一个字节。您将使用:Bfile_ReadFile_OS(hFile, buffer, 1, 10);
这会将1个字节存储到在位置10处读取的缓冲区中。假设您只是想按顺序读取数据,让该位置随每次读取一起移动。在这种情况下,可以将readpos设置为-1,它将使用存储在文件句柄中的位置。Bfile_ReadFile_OS(hFile, buffer+0, 1, 0); //将位置设置为0并读取1个字节
Bfile_ReadFile_OS(hFile, buffer+1, 1, -1); //使用位置1,由上一个函数移动
您也可以使用Bfile_SeekFile_OS,但完全不需要读取它。现在,完成文件操作后,需要关闭它。为此,您将使用Bfile_CloseFile_OS。只是:Bfile_CloseFile_OS(hFile);
还有一些其他功能可能会有所帮助。如果要打开文件,但不知道文件的大小,则可以使用Bfile_GetFileSize_OS来获取大小。 FIXME:这是一个猜测。如果调用Bfile_GetFileSize_OS,它将返回int pos位置文件中的剩余字节。它可能允许您使用-1使用存储在文件句柄中的当前位置。
[*]重命名条目:注意:此功能不在任何已发布的SDK中。 它仅存在于libfxcg的AHelper分支中。
您已经制作好文件和文件夹,一切正常。 假设您想让用户四处移动东西。 当您要移动文件时出现问题。 幸运的是,可以使用Bfile_RenameEntry重命名文件或文件夹。 请记住,路径名的用法与所有其他Bfile函数相同。 这是重命名文件的示例:#define CREATEMODE_FILE 1
//这些不在PrizmSDK中,但更容易记住。
#define FILE_PATH "\\\\fls0\\File.txt"
#define NEW_PATH "\\\\fls0\\File2.old"

unsigned short pFile; //创建缓冲区
unsigned short pFile2; //创建另一个缓冲区
int size = 128;

Bfile_StrToName_ncpy(pFile, (unsigned char*)FILE_PATH, sizeof(FILE_PATH));
Bfile_StrToName_ncpy(pFile2, (unsigned char*)NEW_PATH, sizeof(NEW_PATH));
Bfile_CreateEntry(pFile, CREATEMODE_FILE, &size);

Bfile_RenameEntry(pFile, pFile2); //自动检测您是否需要文件或文件夹
[*]a
[*]查找和列出文件和文件夹:通过Prizm的操作系统,您可以通过指定路径(和文件名中的一个'*'通配符)来查找/列出文件和文件夹。 Bfile_FindFirst将初始化查找句柄并搜索第一个匹配项。 如果没有匹配项或路径无效,则应注意返回值。 请注意,您将使用16位字符串来执行此操作。unsigned short filter, found;
int ret, handle;
file_type_t info; //有关此结构的定义,请参见Bfile_FindFirst

Bfile_strToName_ncpy(filter, "\\\\fls0\\*.g3a", 0x50); //过度杀伤

ret = Bfile_FindFirst(filter, &handle, found, &info);

if(ret == -16)
PrintXY(1,1,"xxNo files found");
else if(ret == 0)
{
unsigned char path;
Bfile_NameToStr_ncpy(path, found, 50);
locate_OS(1,1);
Print_OS(path,0,0);
}

Bfile_FindClose(handle);要从查找句柄读取所有文件和文件夹,请使用Bfile_FindNext。//注意,我正在使用uClibc ++。 您可以改用itoa和朋友
#include <iostream>
using namespace std;

unsigned short filter, found;
int ret, handle;
file_type_t info; //有关此结构的定义,请参见Bfile_FindFirst

Bfile_strToName_ncpy(filter, "\\\\fls0\\*.g3a", 0x50); //过度伤害

ret = Bfile_FindFirst(filter, &handle, found, &info);

while(ret == 0)
unsigned char path;
Bfile_NameToStr_ncpy(path, found, 50);
cout << path << " :: " << info.fsize << endl;

ret = Bfile_FindNext(handle, found, &info);
}

Bfile_FindClose(handle);
[*]例:注意:PrizmSDK 0.3具有这些功能的问题。 您可以使用已修复这些功能的补丁程序版本,以及其他已更改的版本。 您可以在Prizm编程门户上找到最新的修补版本。 #include <stdlib.h>
#include <fxcg/keyboard.h>
#include <fxcg/display.h>
#include <fxcg/file.h>
#define CREATEMODE_FILE 1
#define CREATEMODE_FOLDER 5
#define READ 0
#define READ_SHARE 1
#define WRITE 2
#define READWRITE 3
#define READWRITE_SHARE 4
#define FOLDER_PATH "\\\\fls0\\Example"
#define FILE_PATH "\\\\fls0\\Example\\File.txt"
#define STR "Hello People"

//轻松打印
int y = 1;
void printi(const char* string, int a)
{
   unsigned char buffer;
   
   itoa(a,buffer);
   
   locate_OS(1,y++);
   Print_OS((unsigned char*)string,0,0);
   Print_OS(buffer,0,0);
}
void prints(const char* string1, const char* string2)
{
   locate_OS(1,y++);
   Print_OS((unsigned char*)string1,0,0);
   Print_OS((unsigned char*)string2,0,0);
}

int main()
{
   unsigned short pFolder, pFile; //创建缓冲区
   int size = 128; // 128字节文件
   int hFile; //文件句柄
   
   Bfile_StrToName_ncpy(pFolder, (unsigned char*)FOLDER_PATH, sizeof(FOLDER_PATH)); //复制
   Bfile_StrToName_ncpy(pFile, (unsigned char*)FILE_PATH, sizeof(FILE_PATH)); //复制
   
   Bfile_CreateEntry_OS(pFolder, CREATEMODE_FOLDER, 0); //首先创建文件夹
   Bfile_CreateEntry_OS(pFile, CREATEMODE_FILE, &size); //将文件放在文件夹中
   
   hFile = Bfile_OpenFile_OS(pFile, READWRITE); //这会以读/写模式打开文件
   Bfile_WriteFile_OS(hFile, STR, sizeof(STR));
   
   size = Bfile_GetFileSize_OS(hFile, 0);
   printi("actual size:", size); //这表明逻辑文件大小不同
   
   char *buffer = (char*)malloc(size);
   printi("seek:",Bfile_SeekFile_OS(hFile, 6)); //移至“人物”之前
   printi("write:",Bfile_WriteFile_OS(hFile, "World!", 7)); //覆盖
   printi("tell:",Bfile_TellFile_OS(hFile)); //打印位置
   Bfile_ReadFile_OS(hFile, buffer, size, 0); //读取整个文件
   Bfile_CloseFile_OS(hFile); //关闭它,因为我们完成了
   Bfile_DeleteEntry(pFolder); //删除文件夹也会删除其中的所有内容!
   
   prints("string:",buffer); //打印“ Hello World!”
   free(buffer);
   
   int key;
   while(1) GetKey(&key);
}
[*]错误代码:
-1-找不到文件夹(Bfile_DeleteEntry)
-3-文件路径无效(Bfile_DeleteEntry,Bfile_CreateEntry_OS)
-13-条目已经存在(Bfile_CreateEntry_OS)

以上内容未完成
System ERROR
REBOOT    :
INITIALIZE:
TLB ERROR
TARGET=D223420F
PC    =081007C0
调试崩溃很有趣! 其实不行 只需进行一点按♂摩,您就可以使用崩溃屏幕上的信息来更好地了解发生了什么问题。
崩溃通常看起来像页面上方显示的代码:
下方的三行是有趣的行,为您提供故障类型,引起故障的内存访问,以及发生故障的PC值(PC的含义取决于异常类型)。 在这种情况下,尝试访问0xD223420F的内存是TLB错误。 通常是一个安全的假设(无论故障类型如何),它是由无效的内存访问引起的。
检查:通过调整链接器选项以发出可重定位的ELF对象文件(而不是默认的平面二进制文件)[您可以通过注释掉prizm.x链接器脚本的第一行来做到这一点] 使用哪些内存区域的想法:$ sh3eb-elf-objdump -hr SDLTest.elf

SDLTest.elf:   file format elf32-sh

Sections:
Idx Name          Size      VMA       LMA       File offAlgn
0 .text         0001b2340030000000300000000000802**4
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
1 .rodata       000033000031b2340031b2340001b2b42**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
2 .data         00000088081000040031e5340001e6042**2
                  CONTENTS, ALLOC, LOAD, DATA
3 .bss          0000225c0810008c0031e5bc0001e68c2**2
                  ALLOC
4 .comment      0000001100000000000000000001e68c2**0
                  CONTENTS, READONLY
5 .debug_info   000033df00000000000000000001e69d2**0
                  CONTENTS, READONLY, DEBUGGING
6 .debug_abbrev 00001b1f000000000000000000021a7c2**0
                  CONTENTS, READONLY, DEBUGGING
7 .debug_loc    00001bed00000000000000000002359b2**0
                  CONTENTS, READONLY, DEBUGGING
8 .debug_aranges 000002b00000000000000000000251882**0
                  CONTENTS, READONLY, DEBUGGING
9 .debug_line   00000bbf0000000000000000000254382**0
                  CONTENTS, READONLY, DEBUGGING
10 .debug_str    0000040e000000000000000000025ff72**0
                  CONTENTS, READONLY, DEBUGGING
11 .debug_frame000003fc0000000000000000000264082**2
                  CONTENTS, READONLY, DEBUGGING
12 .debug_ranges 000001e80000000000000000000268042**0
                  CONTENTS, READONLY, DEBUGGING
.debug_ *节现在可以安全地忽略,因为它们提供了地址到名称的机器可读映射。 特别感兴趣的是.text,.data和.bss节,它们分别包含代码,初始化的可写数据和未初始化的可写数据。

参考错误消息,我们尝试访问0xD223420F的内存,该内存远远超出了预期范围。 PC是0x081007C0,这是可疑的-位于.bss中,不应从中执行代码。 这通常是堆栈被破坏的症状,并且由于执行伪代码而导致调试非常困难,并且我们无法检索堆栈跟踪以更早发现问题所在。

似乎该特定崩溃是由NULL指针取消引用引起的,这是不寻常的(不会期望使系统开始在.bss中执行)。 随着更多实验的进行,该页面可能还会有更多内容。
异常名称:“系统错误”对话框的第三(四)行告诉您操作系统处理的异常。这使您了解PC上的代码出了什么问题。转换地址是调用的异常处理程序的地址。 VBR是存储在0xA0000000的地址。
ADDRESS(x)

原因:如果存在数据地址错误,则抛出此异常。如果跨字边界访问一个字,跨长字边界访问一个长字或跨四字边界访问一个四字,则可能导致这种情况。当使用的指令地址不是字对齐时,也可能会调用它。如果在读取或写入周期中发生异常,则(x)将为R或W。

VBR偏移量:0x100

异常代码:读取时为0x0E0,写入时为0x100

优先级:5

可跳过:是
PROTECT(x)

原因:尚未确认,但这可能是由于对受保护内存的读取或写入引起的。如果在读取或写入周期中发生异常,则(x)将为R或W。

VBR偏移量:0x100

异常代码:读取时为0x0A0,写入时为0x0C0

优先级:7

可跳过:未知
INTERRUPT

原因:这是由TRAPA #imm(无条件陷阱)程序集操作码引起的,还是由非法的插槽指令异常引起的(有关详细信息,请参阅SH4a程序集手册)。

VBR偏移量:0x100

异常代码:0x160

优先级:4

可跳过:未知

遇到此异常的一个示例是进入诊断模式,按3、9、2,F1。屏幕上显示“系统错误”消息,并带有“中断”,但未显示目标和PC行。尽管有文字说明,但EXIT不能用于重启。
Illegal Code Err

原因:假定是由于调用未知指令或操作码产生一般错误(例如无效使用的分支操作码产生异常)引起的。

VBR偏移量:0x100

异常代码:0x180

优先级:4

可跳过:未知
TLB ERROR

原因:存在对虚拟内存的内存访问,该内存未映射到UTLB页面表中的物理内存页面(如果访问来自指令提取,则可能是ITLB页面表),并且操作系统无法处理它。请注意,实际异常是MMU的正常行为,它依赖于OS进行处理而不会产生错误。如果操作系统无法处理,则会发生这种情况。

VBR偏移量:0x400

异常代码:0x040(如果这是来自读取的UTLB高速缓存中的TLB丢失(如果这是一条指令提取,也可能是ITLB的未命中),0x060(如果这是来自内存写入的UTLB页表中的TLB丢失) 。

优先级:如果是ITLB未命中,则为2;如果是UTLB未命中,则为6。

可跳过:未知


diaowinner 发表于 2020-3-3 20:50:28

注:这也是有生之年了

diaowinner 发表于 2020-3-3 21:40:42

怎么没有页数了?
页: [1]
查看完整版本: 卡西欧Prizm计算器如何编程?