Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cannot download specific variables from TI-92 II #65

Open
Jonson26 opened this issue Aug 15, 2023 · 9 comments
Open

Cannot download specific variables from TI-92 II #65

Jonson26 opened this issue Aug 15, 2023 · 9 comments

Comments

@Jonson26
Copy link

OS: Kubuntu 22.04.2 LTS x86_64
Software:
TiLP2 - Tilp Is a Linking Program - 1.18
Framework version (cables=1.3.5, files=1.1.7, calcs=1.1.9, conv=1.1.5)
Cable: Silverlink
Calculator: TI-92 II
Expected behavior:
Clicking on folders in variable list expands them to show specific variables
Right-clicking those variables allows the user to download them
Actual behavior:
Only full backup possible

@debrouxl
Copy link
Owner

I fixed a bug related to 92 support after TILP II 1.18, but the commit message mentions dirlist being fixed, not recv.

Could you clean up your distro libti*+gfm+tilp packages if any, use the standard user build script from this repo ( https://github.com/debrouxl/tilp_and_gfm/raw/master/tilp/trunk/build/scripts/install_tilp.sh ) to build libti*+gfm+tilp after installing the build dependencies listed by the script, and try again ? Thanks in advance :)

@soulsource
Copy link

soulsource commented Jan 2, 2025

I have run into the same issue, and debrouxl/tilibs@7659920 seems to fix the directory listing for me.

However, even with it I still cannot download variables, but that might be related to my cable - will debug further.

@soulsource
Copy link

I've now added some debug output to dbus_recv_header, and it seems that at least for my calculator the ACK packet (0x89, 0x56) is not followed by a packet size when receiving a variable, but rather directly the variable header (the bytes that end up in the length variable are 0x89 and 0x06).

My calculator is a regular TI-92, with Firmware 1.12, by the way.

@soulsource
Copy link

soulsource commented Jan 3, 2025

Okay, I am far from knowledgable enough with the codebase (or TI calculators other than the one I own) to know if this is a proper fix, or if it breaks any other calculator models, so I won't open a Pull Request for this. However, this patch (in addition to the mentioned dirlist patch) allows me to receive variables from my calculator:

(Edit: This patch is against libticalcs2-1.1.9, not against the latest repo state.)

--- libticalcs2-1.1.9/src/calc_9x.c	2016-09-10 21:45:22.000000000 +0200
+++ libticalcs2-1.1.9-patched/src/calc_9x.c	2025-01-03 10:32:13.433454866 +0100
@@ -62,6 +62,7 @@
 #define SEND_EOT(handle) (handle->model != CALC_TI92 ? ti89_send_EOT(handle) : ti92_send_EOT(handle))
 
 #define RECV_ACK(handle, status) (handle->model != CALC_TI92 ? ti89_recv_ACK(handle, status) : ti92_recv_ACK(handle, status))
+#define RECV_ACK_NO_SIZE(handle, status) (handle->model != CALC_TI92 ? ti89_recv_ACK(handle, status) : ti92_recv_ACK_NO_SIZE(handle))
 #define RECV_VAR(handle, varsize, vartype, varname) (handle->model != CALC_TI92 ? ti89_recv_VAR(handle, varsize, vartype, varname) : ti92_recv_VAR(handle, varsize, vartype, varname))
 #define RECV_XDP(handle, length, data) (handle->model != CALC_TI92 ? ti89_recv_XDP(handle, length, data) : ti92_recv_XDP(handle, length, data))
 #define RECV_CTS(handle) (handle->model != CALC_TI92 ? ti89_recv_CTS(handle) : ti92_recv_CTS(handle))
@@ -851,7 +852,7 @@
 static int		recv_var	(CalcHandle* handle, CalcMode mode, FileContent* content, VarRequest* vr)
 {
 	int ret = 0;
-	uint16_t status;
+	uint16_t status = 0;
 	VarEntry *ve;
 	uint16_t unused;
 	char varname[20];
@@ -867,7 +868,7 @@
 	ret = SEND_REQ(handle, 0, vr->type, varname);
 	if (!ret)
 	{
-		ret = RECV_ACK(handle, &status);
+		ret = RECV_ACK_NO_SIZE(handle, &status);
 		if (!ret)
 		{
 			if (status != 0)
diff '--color=auto' -ur libticalcs2-1.1.9/src/cmd68k.c libticalcs2-1.1.9-patched/src/cmd68k.c
--- libticalcs2-1.1.9/src/cmd68k.c	2016-10-02 21:58:25.000000000 +0200
+++ libticalcs2-1.1.9-patched/src/cmd68k.c	2025-01-03 10:31:42.285229070 +0100
@@ -632,6 +632,29 @@
 	return ti68k_recv_ACK(handle, status, 1);
 }
 
+TIEXPORT3 int TICALL ti92_recv_ACK_NO_SIZE(CalcHandle* handle)
+{
+	uint8_t host, cmd;
+	int ret;
+
+	VALIDATE_HANDLE(handle);
+	ret = dbus_recv_ack_no_len(handle, &host, &cmd);
+	if (ret)
+	{
+		return ret;
+	}
+
+	if (cmd != DBUS_CMD_ACK)
+	{
+		return ERR_INVALID_CMD;
+	}
+
+	ticalcs_info(" TI92->PC: ACK");
+
+	return 0;
+
+}
+
 TIEXPORT3 int TICALL ti68k_recv_CNT(CalcHandle* handle)
 {
 	uint8_t host, cmd;
diff '--color=auto' -ur libticalcs2-1.1.9/src/cmd68k.h libticalcs2-1.1.9-patched/src/cmd68k.h
--- libticalcs2-1.1.9/src/cmd68k.h	2016-10-02 21:58:25.000000000 +0200
+++ libticalcs2-1.1.9-patched/src/cmd68k.h	2025-01-03 10:35:23.185877305 +0100
@@ -103,6 +103,7 @@
 #define ti92_recv_SKP(handle, rej_code) ti68k_recv_SKP(handle, rej_code)
 #define ti92_recv_XDP(handle, length, data) ti68k_recv_XDP(handle, length, data)
 TIEXPORT3 int TICALL ti92_recv_ACK(CalcHandle *handle, uint16_t * status);
+TIEXPORT3 int TICALL ti92_recv_ACK_NO_SIZE(CalcHandle *handle);
 #define ti92_recv_CNT(handle) ti68k_recv_CNT(handle)
 #define ti92_recv_EOT(handle) ti68k_recv_EOT(handle)
 TIEXPORT3 int TICALL ti92_recv_RTS(CalcHandle *handle, uint32_t * varsize, uint8_t * vartype, char *varname);
diff '--color=auto' -ur libticalcs2-1.1.9/src/dbus_pkt.c libticalcs2-1.1.9-patched/src/dbus_pkt.c
--- libticalcs2-1.1.9/src/dbus_pkt.c	2016-10-02 21:58:25.000000000 +0200
+++ libticalcs2-1.1.9-patched/src/dbus_pkt.c	2025-01-03 10:12:20.487058776 +0100
@@ -341,3 +341,22 @@
 
 	return ret;
 }
+
+TIEXPORT3 int TICALL dbus_recv_ack_no_len(CalcHandle *handle, uint8_t* host, uint8_t* cmd)
+{
+	int ret = 0;
+	uint8_t buf[4] = {0};
+
+	VALIDATE_HANDLE(handle);
+	VALIDATE_NONNULL(host);
+	VALIDATE_NONNULL(cmd);
+
+	// Any packet has always at least 2 bytes (MID, CID)
+	ret = ticables_cable_recv(handle->cable, buf, 2);
+	if (!ret)
+	{
+		*host = buf[0];
+		*cmd = buf[1];
+	}
+	return ret;
+}
diff '--color=auto' -ur libticalcs2-1.1.9/src/ticalcs.h libticalcs2-1.1.9-patched/src/ticalcs.h
--- libticalcs2-1.1.9/src/ticalcs.h	2016-10-02 21:58:25.000000000 +0200
+++ libticalcs2-1.1.9-patched/src/ticalcs.h	2025-01-03 10:10:10.286115863 +0100
@@ -931,6 +931,8 @@
 	TIEXPORT3 int TICALL dbus_recv(CalcHandle *handle, uint8_t* host, uint8_t* cmd, uint16_t* length, uint8_t* data);
 	TIEXPORT3 int TICALL dbus_recv_header(CalcHandle *handle, uint8_t* host, uint8_t* cmd, uint16_t* length);
 	TIEXPORT3 int TICALL dbus_recv_data(CalcHandle *handle, uint16_t* length, uint8_t* data);
+	// special handling of a TI-92 quirk when receiving variables - unlike all other situations does not read length
+	TIEXPORT3 int TICALL dbus_recv_ack_no_len(CalcHandle *handle, uint8_t* host, uint8_t* cmd);
 
 	// dusb_rpkt.c
 	TIEXPORT3 int TICALL dusb_send(CalcHandle *handle, DUSBRawPacket* pkt);

@debrouxl
Copy link
Owner

debrouxl commented Jan 3, 2025

Interesting, thanks for the investigation and patch :)
Have you tested whether active ("non-silent", in libti*/tilp parlance) receive, i.e. putting TILP in receive mode and sending the variable from the calculator through e.g. the VAR-Link, is affected by the same bug ?

Since ti89_recv_ACK and ti92_recv_ACK both call into ti68k_recv_ACK with an argument which makes it possible to distinguish between 92 and other TI-68k models, and all functions end up calling into dbus_recv and therefore dbus_recv_header, alternative ways to implement this fix would have been to modify ti68k_recv_ACK or dbus_recv_header. One thing is sure: many other code paths in that file call these functions, so if this silent variable receive functionality is the only one which has that quirk (to be confirmed by testing), a change of minimal impact, like what you did here, is certainly the one that makes sense.

And you probably don't have multiple 92 calculators with different OS versions for testing fixes, but that should be OK: TILP on top of patched libticalcs communicating with 92 ROM dumps running on TIEmu through virtual linking ought to do the job.
That's the beauty of the libti* framework. Some balk at its complexity, but a while after becoming the maintainer, I came to understand that not only some more or less significant use cases would suffer if one of the layers were missing, but that there aren't even enough layers :)

@soulsource
Copy link

I'm trying to figure out how to set TILP into non-silent receive mode, but I'm only seeing a call to ticalcs_calc_recv_var_ns2() in a TI82 and 85 specific code-path.

Am I missing something, or is this functionality not exposed for TI92?

@debrouxl
Copy link
Owner

debrouxl commented Jan 3, 2025

On the lower levels, the 92 supports non-silent linking: calc_92 struct in calc_9x.c, both the feature mask and the function pointers :)

By default, in TILP, it's a "Receive variables from non-silent calculators" (or French/German-localized translation thereof) button in the left pane, below the menu.

@soulsource
Copy link

I'll need to look further (later), but for now that button doesn't seem to do much for me, unless I already select a variable in the dir-list to download.

@soulsource
Copy link

soulsource commented Jan 10, 2025

By the way, I've had a quick look at the current code, and it really seems that non-silent recv is not hooked up for any calcs that aren't a TI82 or TI 85:

// Receive
TILP_EXPORT void on_tilp_button5_clicked(GtkButton* button, gpointer user_data)
{
on_tilp_recv();
}

void on_tilp_recv(void)
{
int ret;
if ((remote.selection1 != NULL) || (remote.selection2 != NULL))
{
if (remote.selection1 != NULL)
{
ret = tilp_calc_recv_var();
if (ret < 0)
return;
else if (ret > 0)
save_group();
}
if (remote.selection2 != NULL)
{
ret = tilp_calc_recv_app();
if (ret != 0)
return;
}
}
else if ((options.calc_model == CALC_TI82) || (options.calc_model == CALC_TI85))
{
ret = tilp_calc_recv_var();
if (ret < 0)
return;
else if (ret > 0)
save_group();
}
clist_refresh();
labels_refresh();
}

int tilp_calc_recv_var(void)
{
if (options.calc_model == CALC_TI82 || options.calc_model == CALC_TI85)
return tilp_calc_recv_var2();
else
return tilp_calc_recv_var1();
return 0;
}

The tilp_calc_recv_var2() function uses non-silent recv:

// TI82 & 85
static int tilp_calc_recv_var2(void)
{
gchar *tmp_filename;
gchar *dst_filename;
VarEntry* ve;
//char *varname;
int err;
char *basename;
//
// Receive one variable or several variables packed into a group.
//
tmp_filename = g_strconcat(g_get_tmp_dir(), G_DIR_SEPARATOR_S, TMPFILE_GROUP,
".", tifiles_fext_of_group(options.calc_model), NULL);
gif->create_pbar_(FNCT_RECV_VAR, _("Receiving var(s)"));
err = ticalcs_calc_recv_var_ns2(calc_handle, MODE_NORMAL, tmp_filename, &ve);
gif->destroy_pbar();
if (err)
{
tilp_err(err);
return -1;
}
// Check for single/group
if (ve)
{
//single
basename = ticonv_varname_to_filename(options.calc_model, ve->name, ve->type);
dst_filename = g_strconcat(local.cwdir, G_DIR_SEPARATOR_S, basename,
".", tifiles_vartype2fext(options.calc_model, ve->type), NULL);
tilp_file_move_with_check(tmp_filename, dst_filename);
tifiles_ve_delete(ve);
ticonv_gfe_free(basename);
g_free(tmp_filename);
g_free(dst_filename);
return 0;
}
else
{
if (!options.recv_as_group)
{
err = tifiles_ungroup_file(tmp_filename, NULL);
if (err)
tilp_err(err);
g_free(tmp_filename);
return 0;
}
else
{
return 1;
}
}
return 0;
}

The tilp_cacl_recv_var1() function uses regular (silent) recv:

// non TI82 & 85
static int tilp_calc_recv_var1(void)
{
int i, l;
int err, ret=0;
FileContent **array;
if (!tilp_remote_selection_ready())
return -1;
if (tilp_calc_isready())
return -1;
gif->create_pbar_(FNCT_RECV_VAR, _("Receiving var(s)"));
l = g_list_length(remote.selection1);
if (l == 1)
{
// One variable
VarEntry *ve = (VarEntry *)remote.selection1->data;
gchar *tmp_filename;
gchar *dst_filename;
char *varname, *fldname;
gtk_update.cnt3 = 1;
gtk_update.max3 = l;
gtk_update.pbar();
gtk_update.refresh();
tmp_filename = g_strconcat(g_get_tmp_dir(), G_DIR_SEPARATOR_S, TMPFILE_GROUP,
".", tifiles_fext_of_group(options.calc_model), NULL);
tcrv1:
err = ticalcs_calc_recv_var2(calc_handle, MODE_NORMAL, tmp_filename, ve);
if (err && err != ERROR_ABORT)
{
tilp_err(err);
ret = gif->msg_box3(_("Question"), _("Action to take?"), _("Retry"), _("Skip"), _("Cancel"));
switch(ret)
{
case BUTTON1: goto tcrv1;
case BUTTON2: break;
default: break;
}
gif->destroy_pbar();
return -1;
}
varname = ticonv_varname_to_filename(options.calc_model, ve->name, ve->type);
fldname = ticonv_varname_to_filename(options.calc_model, ve->folder, -1);
if (tifiles_has_folder(options.calc_model) && options.calc_model != CALC_NSPIRE)
dst_filename = g_strconcat(local.cwdir, G_DIR_SEPARATOR_S,
fldname, ".", varname, ".",
tifiles_vartype2fext(options.calc_model, ve->type), NULL);
else
dst_filename = g_strconcat(local.cwdir, G_DIR_SEPARATOR_S,
varname, ".",
tifiles_vartype2fext(options.calc_model, ve->type), NULL);
tilp_file_move_with_check(tmp_filename, dst_filename);
ticonv_gfe_free(fldname);
ticonv_gfe_free(varname);
g_free(tmp_filename);
g_free(dst_filename);
}
else
{
// Multiple variables (single or group depending on global option)
GList *sel;
gchar *src_filename;
gchar *tmp_filename;
gchar *dst_filename;
array = tifiles_content_create_group(l);
if (array == NULL)
return -1;
for(sel = remote.selection1, i = 0; sel; sel = sel->next, i++)
{
VarEntry *ve = (VarEntry *)sel->data;
gtk_update.cnt3 = i+1;
gtk_update.max3 = l;
gtk_update.pbar();
gtk_update.refresh();
tcrv2:
array[i] = tifiles_content_create_regular(options.calc_model);
err = ticalcs_calc_recv_var(calc_handle, MODE_NORMAL, array[i], ve);
if (err && err != ERROR_ABORT)
{
tilp_err(err);
ret = gif->msg_box3(_("Question"), _("Action to take?"), _("Retry"), _("Skip"), _("Cancel"));
switch(ret)
{
case BUTTON1: goto tcrv2;
case BUTTON2: continue;
default: break;
}
gif->destroy_pbar();
return -1;
}
}
if (options.recv_as_group)
{
FileContent* content;
tmp_filename = g_strconcat(g_get_tmp_dir(), G_DIR_SEPARATOR_S, TMPFILE_GROUP,
".", tifiles_fext_of_group(options.calc_model), NULL);
err = tifiles_group_contents(array, &content);
if (err)
{
tilp_err(err);
tifiles_content_delete_group(array);
g_free(tmp_filename);
goto tcrv;
}
strcpy(content->comment, tifiles_comment_set_group());
err = tifiles_file_write_regular(tmp_filename, content, NULL);
if (err)
{
tilp_err(err);
tifiles_content_delete_group(array);
g_free(tmp_filename);
goto tcrv;
}
tifiles_content_delete_regular(content);
g_free(tmp_filename);
ret = 1;
}
else
{
tilp_file_chdir(g_get_tmp_dir());
for(i = 0; i < l; i++)
{
tmp_filename = NULL;
err = tifiles_file_write_regular(NULL, array[i], &tmp_filename);
if (err)
{
tilp_err(err);
break;
}
if (tmp_filename != NULL)
{
src_filename = g_strconcat(g_get_tmp_dir(), G_DIR_SEPARATOR_S,
g_path_get_basename(tmp_filename), NULL);
dst_filename = g_strconcat(local.cwdir, G_DIR_SEPARATOR_S,
g_path_get_basename(tmp_filename), NULL);
g_free(tmp_filename);
tilp_file_move_with_check(src_filename, dst_filename);
g_free(dst_filename);
g_free(src_filename);
}
}
tilp_file_chdir(local.cwdir);
}
tifiles_content_delete_group(array);
}
tcrv:
gif->destroy_pbar();
return ret;
}

I don't know when I have the time to experiment, but it might not be too hard to add a third branch to tilp_cacl_recv_var1() that uses non-silent recv if g_list_length(remote.selection1) == 0...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants