Compare commits
10 Commits
21cc24d8b7
...
6c5c689408
Author | SHA1 | Date |
---|---|---|
Tobias Mädel | 6c5c689408 | |
Tobias Mädel | 7c3d48a88a | |
Tobias Mädel | 8249bde841 | |
Tobias Mädel | 260198604d | |
Tobias Mädel | 41dd653925 | |
Tobias Mädel | c35ea6b0c5 | |
Tobias Mädel | c171739cf0 | |
Tobias Mädel | af72743536 | |
Tobias Mädel | eeab1daed1 | |
Tobias Mädel | 6c411991f5 |
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2021 Tobias Mädel
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
41
README.md
41
README.md
|
@ -1,10 +1,43 @@
|
|||
# fxIP
|
||||
### TCP/IP stack and IRC client for Casio fx-9860/9750 calculators
|
||||
|
||||
|
||||
<img src="https://screenshot.tbspace.de/miceroxwgfj.jpg" width="350"/> <img src="https://screenshot.tbspace.de/bjwklegfnmp.jpg" width="350"/>
|
||||
|
||||
![Screenshot of ping](https://screenshot.tbspace.de/uwaontfeqlk.png)
|
||||
|
||||
[YouTube video of fxIP's IRC client, connecting to irc.libera.chat](https://www.youtube.com/watch?v=afkrucsMMrc)
|
||||
[YouTube video of fxTerm, a simple RS232 terminal application](https://www.youtube.com/watch?v=epFX8K0dhdY)
|
||||
|
||||
fxIP is a port of [uIP 1.0](https://github.com/adamdunkels/uip) to Casio fx-9750/fx-9860 calculators.
|
||||
It (currently) requires calculators with a SuperH SH4a CPU, needs quite a bit of SRAM.
|
||||
|
||||
fxIP connects to IP networks via SLIP encapsulation over the 3-pin 2.5mm 5V serial port/UART.
|
||||
By default, it connects to irc.libera.chat (without SSL).
|
||||
|
||||
[TobleMiner](https://github.com/TobleMiner) wrote the SCIF UART driver, the ringbuffer implementation, the object-log storage,
|
||||
which is used to store IRC and log messages for display and fixed issues with endianess on SuperH and the SLIP encapsulation.
|
||||
|
||||
### Network setup (needs root)
|
||||
```
|
||||
sudo slattach -s 115200 -p slip -v -d -L /dev/ttyUSB0
|
||||
sudo ip addr add 10.10.10.1/24 dev sl0
|
||||
sudo ip link set mtu 576 dev sl0
|
||||
sudo ip link set sl0 up
|
||||
slattach -s 115200 -p slip -v -d -L /dev/ttyUSB0
|
||||
ip addr add 10.10.10.1/24 dev sl0
|
||||
ip link set mtu 576 dev sl0
|
||||
ip link set sl0 up
|
||||
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
|
||||
echo "1" > /proc/sys/net/ipv4/ip_forward
|
||||
```
|
||||
|
||||
### Building Add-In
|
||||
Requires [fxsdk](https://gitea.planet-casio.com/Lephenixnoir/fxsdk) and gint to build.
|
||||
gint needs to be patched using gint.patch before building.
|
||||
```
|
||||
touch src/main.c && make clean && fxsdk build-fx && cp -f Fxip.g1a ~/Exchange/Test/
|
||||
```
|
||||
|
||||
|
||||
### Credits
|
||||
fxIP uses the following fantastic projects:
|
||||
[fxsdk](https://gitea.planet-casio.com/Lephenixnoir/fxsdk) by [Lephenixnoir](https://gitea.planet-casio.com/Lephenixnoir)
|
||||
[c-object-log](https://github.com/TobleMiner/c-object-log) by [TobleMiner](https://github.com/TobleMiner)
|
||||
[uIP 1.0](https://github.com/adamdunkels/uip) by [Adam Dunkels](https://github.com/adamdunkels)
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
diff -Naur gint-orig/fx9860g.ld gint-mod/fx9860g.ld
|
||||
--- gint-orig/fx9860g.ld 2021-05-12 09:16:14.000000000 +0200
|
||||
+++ gint-mod/fx9860g.ld 2021-07-13 21:46:59.045357371 +0200
|
||||
@@ -25,7 +25,7 @@
|
||||
0x1100 bytes near the end of the user RAM, which is larger; the 6k
|
||||
left for the user are honored in both cases. Unused memory from the
|
||||
exposed 6k and non-exposed memory is available through malloc(). */
|
||||
- ram (rw): o = 0x08100200, l = 6k
|
||||
+ ram (rw): o = 0x08100200, l = 30k
|
||||
|
||||
/* This region represents the first block of user RAM. Linker arranges
|
||||
sections as if linked to address 0, then gint's runtime determines
|
||||
diff -Naur gint-orig/include/gint/intc.h gint-mod/include/gint/intc.h
|
||||
--- gint-orig/include/gint/intc.h 2021-05-12 09:16:14.000000000 +0200
|
||||
+++ gint-mod/include/gint/intc.h 2021-07-13 21:46:59.052024044 +0200
|
||||
@@ -36,6 +36,8 @@
|
||||
INTC_DMA_DEI4,
|
||||
INTC_DMA_DEI5,
|
||||
INTC_DMA_DADERR,
|
||||
+ /* Serial Communication Interface with FIFO (SCIF0) */
|
||||
+ INTC_SCIF0,
|
||||
/* Real-Time Clock [RTC]; a single IPR covers all 3 interrupts */
|
||||
INTC_RTC_ATI,
|
||||
INTC_RTC_PRI,
|
||||
diff -Naur gint-orig/src/intc/intc.c gint-mod/src/intc/intc.c
|
||||
--- gint-orig/src/intc/intc.c 2021-05-12 09:16:14.000000000 +0200
|
||||
+++ gint-mod/src/intc/intc.c 2021-07-13 21:46:59.058690718 +0200
|
||||
@@ -57,6 +57,8 @@
|
||||
{ IPRF, 0x0f00, IMR5, 0x10, _ },
|
||||
{ IPRF, 0x0f00, IMR5, 0x20, _ },
|
||||
{ IPRF, 0x0f00, IMR5, 0x40, _ },
|
||||
+ /* SCIF */
|
||||
+ { IPRG, 0xf000, IMR5, 0x01, _ },
|
||||
/* RTC */
|
||||
{ IPRK, 0xf000, IMR10, 0x04, IPRA, 0x000f },
|
||||
{ IPRK, 0xf000, IMR10, 0x02, IPRA, 0x000f },
|
||||
diff -Naur gint-orig/src/kernel/syscalls.S gint-mod/src/kernel/syscalls.S
|
||||
--- gint-orig/src/kernel/syscalls.S 2021-05-12 09:16:14.000000000 +0200
|
||||
+++ gint-mod/src/kernel/syscalls.S 2021-07-13 21:46:59.058690718 +0200
|
||||
@@ -40,6 +40,18 @@
|
||||
.global ___GetVRAMAddress
|
||||
.global ___ConfigureStatusArea
|
||||
|
||||
+.global ___Serial_Open
|
||||
+.global ___Serial_Close
|
||||
+.global ___Serial_ReadByte
|
||||
+.global ___Serial_ReadBytes
|
||||
+.global ___Serial_WriteByte
|
||||
+.global ___Serial_WriteBytes
|
||||
+.global ___Serial_GetRxBufferSize
|
||||
+.global ___Serial_GetTxBufferFreeCapacity
|
||||
+.global ___Serial_ClearReceiveBuffer
|
||||
+.global ___Serial_ClearTransmitBuffer
|
||||
+.global ___OS_InnerWait_ms
|
||||
+
|
||||
#define syscall_(id, syscall_table) \
|
||||
mov.l syscall_table, r2 ;\
|
||||
mov.l 1f, r0 ;\
|
||||
@@ -103,6 +115,32 @@
|
||||
___GetVRAMAddress:
|
||||
syscall(0x135)
|
||||
|
||||
+
|
||||
+___Serial_Open:
|
||||
+ syscall(0x418)
|
||||
+___Serial_Close:
|
||||
+ syscall(0x419)
|
||||
+___Serial_ReadByte:
|
||||
+ syscall(0x040C)
|
||||
+___Serial_ReadBytes:
|
||||
+ syscall(0x040D)
|
||||
+___Serial_WriteByte:
|
||||
+ syscall(0x040E)
|
||||
+___Serial_WriteBytes:
|
||||
+ syscall(0x040F)
|
||||
+___Serial_GetRxBufferSize:
|
||||
+ syscall(0x0411)
|
||||
+___Serial_GetTxBufferFreeCapacity:
|
||||
+ syscall(0x0412)
|
||||
+___Serial_ClearReceiveBuffer:
|
||||
+ syscall(0x0413)
|
||||
+___Serial_ClearTransmitBuffer:
|
||||
+ syscall(0x0414)
|
||||
+
|
||||
+___OS_InnerWait_ms:
|
||||
+ syscall(0x0420)
|
||||
+
|
||||
+
|
||||
syscall_table:
|
||||
.long 0x80010070
|
46
src/hayes.c
46
src/hayes.c
|
@ -4,18 +4,26 @@
|
|||
uint8_t hayes_response_buffer[128];
|
||||
uint16_t hayes_response_buffer_offset = 0;
|
||||
|
||||
int hayes_send_and_read(char *command, char* readbuf, char* readbuflength)
|
||||
int hayes_send(char *command)
|
||||
{
|
||||
if (strlen(command) != 0)
|
||||
{
|
||||
scif_write(command, strlen(command));
|
||||
scif_write("\r\n", 2);
|
||||
}
|
||||
}
|
||||
|
||||
int hayes_read(char *readbuf, uint16_t readbuflength, int timeout, int ignore_echo)
|
||||
{
|
||||
hayes_response_buffer_offset = 0;
|
||||
|
||||
scif_write(command, strlen(command));
|
||||
scif_write("\r\n", 2);
|
||||
uint8_t echo = ignore_echo;
|
||||
|
||||
uint8_t finished = 0;
|
||||
uint8_t echo = 0;
|
||||
while (!finished)
|
||||
uint32_t start = clock_time();
|
||||
|
||||
while (1)
|
||||
{
|
||||
int byte = scif_read();
|
||||
int byte = scif_read();
|
||||
if (byte >= 0)
|
||||
{
|
||||
hayes_response_buffer[hayes_response_buffer_offset++] = byte;
|
||||
|
@ -29,14 +37,32 @@ int hayes_send_and_read(char *command, char* readbuf, char* readbuflength)
|
|||
}
|
||||
else
|
||||
{
|
||||
memcpy(readbuf, hayes_response_buffer, MIN(hayes_response_buffer_offset, readbuflength));
|
||||
memcpy(readbuf, hayes_response_buffer, MIN(hayes_response_buffer_offset + 1, readbuflength));
|
||||
return 1;
|
||||
}
|
||||
|
||||
hayes_response_buffer_offset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (timeout)
|
||||
{
|
||||
if (start + timeout < clock_time())
|
||||
{
|
||||
fxip_log("timeout");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hayes_send_and_read(char *command, char *readbuf, uint16_t readbuflength)
|
||||
{
|
||||
// flush all previous content in the read
|
||||
scif_read_flush();
|
||||
|
||||
hayes_send(command);
|
||||
|
||||
return hayes_read(readbuf, readbuflength, 20, 0);
|
||||
}
|
|
@ -1,4 +1,6 @@
|
|||
#pragma once
|
||||
#include <stdint.h>
|
||||
|
||||
int hayes_send_and_read(char *command, char* readbuf, char* readbuflength);
|
||||
int hayes_send_and_read(char *command, char *readbuf, uint16_t readbuflength);
|
||||
int hayes_read(char *readbuf, uint16_t readbuflength, int timeout, int ignore_echo);
|
||||
int hayes_send(char *command);
|
40
src/main.c
40
src/main.c
|
@ -27,6 +27,7 @@ static int casioos_Serial_Close()
|
|||
return 0;
|
||||
}
|
||||
|
||||
//uint8_t atdt_call_buffer[128];
|
||||
|
||||
int main(void)
|
||||
{
|
||||
|
@ -34,36 +35,31 @@ int main(void)
|
|||
scif_init();
|
||||
|
||||
ui_init();
|
||||
fxip_log("");
|
||||
fxip_log("fxIP, build date:");
|
||||
fxip_log(&__TIMESTAMP__[4]);
|
||||
fxip_log("manawyrm & TobleMiner");
|
||||
|
||||
clock_setup();
|
||||
|
||||
/*uint32_t lastscifwritetime = clock_time();
|
||||
/*while (hayes_send_and_read("ATI3", atdt_call_buffer, sizeof(atdt_call_buffer)) == 0)
|
||||
{
|
||||
uint32_t start = clock_time();
|
||||
while (start + 1 > clock_time());
|
||||
}
|
||||
fxip_log("read 1:");
|
||||
fxip_log(atdt_call_buffer);
|
||||
|
||||
fxip_log("Calling **2");
|
||||
|
||||
scif_read_flush();
|
||||
hayes_send("ATDT **2");
|
||||
|
||||
while (true)
|
||||
{
|
||||
/*if (clock_time() % 30 == 0 && lastscifwritetime != clock_time())
|
||||
{
|
||||
lastscifwritetime = clock_time();
|
||||
|
||||
if (hayes_send_and_read("ATI2", datatemp, 128))
|
||||
{
|
||||
fxip_printf("recv: %s", datatemp);
|
||||
}
|
||||
}
|
||||
|
||||
if (ui_handle_keyboard())
|
||||
{
|
||||
// Exit
|
||||
gint_world_switch(GINT_CALL(casioos_Serial_Close));
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (clock_time() % 10 == 0)
|
||||
{
|
||||
ui_update();
|
||||
}
|
||||
hayes_read(atdt_call_buffer, sizeof(atdt_call_buffer), 0, 1);
|
||||
fxip_log("read 2:");
|
||||
fxip_log(atdt_call_buffer);
|
||||
}*/
|
||||
|
||||
network_init();
|
||||
|
|
|
@ -33,8 +33,7 @@ void network_init()
|
|||
//httpd_init();
|
||||
irc_init();
|
||||
|
||||
|
||||
uip_ipaddr(ipaddr, 188,240,145,102);
|
||||
uip_ipaddr(ipaddr, 163,123,192,192);
|
||||
//uip_ipaddr(ipaddr, 10,10,10,1);
|
||||
irc_connect(ipaddr);
|
||||
|
||||
|
|
|
@ -68,6 +68,11 @@ int scif_read()
|
|||
return -1;
|
||||
}
|
||||
|
||||
int scif_read_flush()
|
||||
{
|
||||
while (scif_read() != -1);
|
||||
}
|
||||
|
||||
static void scif_interrupt()
|
||||
{
|
||||
// fill TX FIFO
|
||||
|
|
|
@ -4,4 +4,5 @@
|
|||
void scif_debug();
|
||||
void scif_write(const void *data, uint16_t len);
|
||||
int scif_read();
|
||||
void scif_init();
|
||||
void scif_init();
|
||||
int scif_read_flush();
|
12
src/ui.c
12
src/ui.c
|
@ -12,6 +12,7 @@
|
|||
#include "uip/irc.h"
|
||||
|
||||
extern struct uip_stats uip_stat;
|
||||
extern const char irc_username[];
|
||||
|
||||
uint8_t cursor_blink = 0;
|
||||
|
||||
|
@ -26,13 +27,12 @@ void ui_cursor_blink()
|
|||
|
||||
void ui_page_irc_message_submit(page_t *page)
|
||||
{
|
||||
unsigned length = snprintf(messagebuffer, sizeof(messagebuffer), "PRIVMSG ##manawyrmtest :%s", page->input_buffer);
|
||||
printflength = snprintf(messagebuffer, sizeof(messagebuffer) - 1, "<%s> %s", irc_username, page->input_buffer);
|
||||
printflength = MIN(sizeof(messagebuffer), printflength);
|
||||
ui_write_log(PAGE_IRC_CHANNEL, 0, 0, messagebuffer, printflength);
|
||||
|
||||
if (length > sizeof(messagebuffer))
|
||||
{
|
||||
length = sizeof(messagebuffer);
|
||||
}
|
||||
messagelength = length;
|
||||
messagelength = snprintf(messagebuffer, sizeof(messagebuffer), "PRIVMSG ##whitequark :%s", page->input_buffer);
|
||||
messagelength = MIN(sizeof(messagebuffer), messagelength);
|
||||
}
|
||||
|
||||
const page_t pages[] = {
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include "psock.h"
|
||||
#include "uip.h"
|
||||
#include "ui.h"
|
||||
#include "util.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
|
@ -14,6 +15,10 @@ static char *localhostname;
|
|||
static const char irc_command_privmsg[] = "PRIVMSG";
|
||||
static const char irc_command_error[] = "ERROR";
|
||||
static const char irc_command_ping[] = "PING";
|
||||
static const char irc_command_join[] = "JOIN";
|
||||
|
||||
const char irc_username[] = "CasioFXIRC";
|
||||
int irc_username_length = 10;
|
||||
|
||||
static int irc_parse_command(irc_message message)
|
||||
{
|
||||
|
@ -27,31 +32,42 @@ static int irc_parse_command(irc_message message)
|
|||
|
||||
if (strncasecmp(message.command, irc_command_privmsg, strlen(message.command)) == 0)
|
||||
{
|
||||
//ui_write_log(PAGE_IRC_CHANNEL, 0, 0, "privmsg", 7);
|
||||
|
||||
whitespace = memchr(message.command_arguments, ' ', strlen(message.command_arguments));
|
||||
if (whitespace == NULL)
|
||||
return;
|
||||
|
||||
ui_write_log(PAGE_IRC_CHANNEL, 0, 0, &whitespace[2], strlen(&whitespace[2]) - 1);
|
||||
whitespace[2 + strlen(&whitespace[2]) - 1] = 0x00;
|
||||
|
||||
// find ! in prefix (which contains the username) and end the string there
|
||||
char *prefixend = memchr(message.prefix, '!', strlen(message.prefix));
|
||||
prefixend[0] = 0x00;
|
||||
|
||||
printflength = snprintf(messagebuffer, sizeof(messagebuffer) - 1, "<%s> %s", message.prefix , &whitespace[2]);
|
||||
printflength = MIN(sizeof(messagebuffer), printflength);
|
||||
|
||||
ui_write_log(PAGE_IRC_CHANNEL, 0, 0, messagebuffer, printflength);
|
||||
return;
|
||||
}
|
||||
|
||||
/*if (strncasecmp(message.command, irc_command_ping, strlen(message.command)) == 0)
|
||||
if (strncasecmp(message.command, irc_command_ping, strlen(message.command)) == 0)
|
||||
{
|
||||
//ui_write_log(PAGE_IRC_CHANNEL, 0, 0, "privmsg", 7);
|
||||
|
||||
whitespace = memchr(message.command_arguments, ' ', strlen(message.command_arguments));
|
||||
if (whitespace == NULL)
|
||||
return;
|
||||
|
||||
ui_write_log(PAGE_IRC_CHANNEL, 0, 0, &whitespace[2], strlen(&whitespace[2]) - 1);
|
||||
|
||||
messagelength = snprintf(messagebuffer, sizeof(messagebuffer) - 1, "PONG %s", message.command_arguments);
|
||||
messagelength = MIN(sizeof(messagebuffer), messagelength);
|
||||
return;
|
||||
}*/
|
||||
}
|
||||
|
||||
ui_write_log(PAGE_IRC_OVERVIEW, 0, 0, message.command_arguments, strlen(message.command_arguments));
|
||||
if (strncasecmp(message.command, irc_command_join, strlen(message.command)) == 0)
|
||||
{
|
||||
ui_write_log(PAGE_IRC_OVERVIEW, 0, 0, "JOIN successful", 15);
|
||||
return;
|
||||
}
|
||||
|
||||
whitespace = memchr(message.command_arguments, ' ', strlen(message.command_arguments));
|
||||
if (whitespace == NULL)
|
||||
return;
|
||||
|
||||
whitespace[2 + strlen(&whitespace[2]) - 1] = 0x00;
|
||||
ui_write_log(PAGE_IRC_OVERVIEW, 0, 0, &whitespace[2], strlen(&whitespace[2]) - 1);
|
||||
}
|
||||
|
||||
static int irc_parse_line(char *data, uint16_t length)
|
||||
|
@ -111,7 +127,7 @@ static int irc_thread(struct irc_state *s)
|
|||
PSOCK_SEND_STR(&s->psock, "nick CasioFXIRC\r\n");
|
||||
PSOCK_SEND_STR(&s->psock, "user CasioFXIRC 0 0 CasioFX\r\n");
|
||||
PSOCK_READTO(&s->psock, '\n');
|
||||
PSOCK_SEND_STR(&s->psock, "JOIN ##manawyrmtest\r\n");
|
||||
PSOCK_SEND_STR(&s->psock, "JOIN ##whitequark\r\n");
|
||||
PSOCK_READTO(&s->psock, '\n');
|
||||
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ typedef enum {
|
|||
|
||||
uint8_t messagebuffer[256];
|
||||
uint16_t messagelength;
|
||||
uint16_t printflength;
|
||||
|
||||
typedef struct irc_state
|
||||
{
|
||||
|
@ -31,11 +32,10 @@ typedef struct irc_state
|
|||
struct psock psock_out;
|
||||
|
||||
uint8_t inputbuffer[128];
|
||||
|
||||
|
||||
} uip_tcp_appstate_t;
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
char *message; // :tungsten.libera.chat 250 asdfCasio :Highest connection count: 6972 (6971 clients) (71075 connections received)
|
||||
uint16_t length;
|
||||
|
||||
|
|
Loading…
Reference in New Issue