Compare commits

...

10 Commits

Author SHA1 Message Date
Tobias Mädel 6c5c689408
Create LICENSE 2022-06-05 11:05:52 +02:00
Tobias Mädel 7c3d48a88a
Update README 2021-07-14 15:46:58 +02:00
Tobias Mädel 8249bde841
Update README.md 2021-07-13 21:51:56 +02:00
Tobias Mädel 260198604d
Add required gint patch 2021-07-13 21:51:26 +02:00
Tobias Mädel 41dd653925
Update README.md 2021-07-12 23:14:22 +02:00
Tobias Mädel c35ea6b0c5
Merge pull request #2 from Manawyrm/irc-and-keyboard
Add README
2021-07-12 20:57:37 +02:00
Tobias Mädel c171739cf0
Add README 2021-07-12 20:38:55 +02:00
Tobias Mädel af72743536
Merge pull request #1 from Manawyrm/irc-and-keyboard
Irc and keyboard
2021-07-12 00:01:37 +02:00
Tobias Mädel eeab1daed1
meh! 2021-07-12 00:01:19 +02:00
Tobias Mädel 6c411991f5
IRC message parsing, PING commands, etc. 2021-07-11 17:22:52 +02:00
12 changed files with 253 additions and 64 deletions

21
LICENSE Normal file
View File

@ -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.

View File

@ -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"/>&nbsp;<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)

90
gint.patch Normal file
View File

@ -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

View File

@ -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);
}

View File

@ -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);

View File

@ -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();

View File

@ -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);

View File

@ -68,6 +68,11 @@ int scif_read()
return -1;
}
int scif_read_flush()
{
while (scif_read() != -1);
}
static void scif_interrupt()
{
// fill TX FIFO

View File

@ -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();

View File

@ -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[] = {

View File

@ -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');

View File

@ -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;