static void do_charset(void) { // set the communication charset to PETSCII strcpy(outbuf, cconv_charsetname(current_charset)); // prepare FS_CHARSET packet packet_set_filled(&outpack, FSFD_CMD, FS_CHARSET, strlen(outbuf)+1); // send the FS_CHARSET packet endpoint->provider->submit_call(endpoint->provdata, FSFD_CMD, &outpack, &outpack, out_callback); // must not wait, as we may be in callback from FS_RESET (from server), // so serial_lock is set }
void rtconfig_pullconfig(int argc, const char *argv[]) { for (int i = 0; i < argc; i++) { if (argv[i][0] == '-' && argv[i][1] == 'X') { do_setopt((char*)argv[i]+2, strlen(argv[i]+2)); } } // prepare FS_RESET packet packet_set_filled(&buspack, FSFD_SETOPT, FS_RESET, 0); // send request, receive in same buffer we sent from endpoint->provider->submit_call(endpoint->provdata, FSFD_SETOPT, &buspack, &buspack, setopt_callback); debug_printf("sent reset packet on fd %d, charset=%d\n", FSFD_SETOPT, current_charset); // send charset command do_charset(); }
uint8_t file_submit_call(uint8_t channel_no, uint8_t type, uint8_t *cmd_buffer, errormsg_t *errormsg, rtconfig_t *rtconf, void (*callback)(int8_t errnum, uint8_t *rxdata), uint8_t iscmd) { assert_not_null(errormsg, "file_submit_call: errormsg is null"); assert_not_null(rtconf, "file_submit_call: rtconf is null"); // check for default drive (here is the place to set the last used one) if (nameinfo.drive == NAMEINFO_LAST_DRIVE) { nameinfo.drive = rtconf->last_used_drive; } else if (nameinfo.drive == NAMEINFO_UNUSED_DRIVE) { // TODO: match CBM behavior nameinfo.drive = rtconf->last_used_drive; } else if (nameinfo.drive < MAX_DRIVES) { // only save real drive numbers as last used default rtconf->last_used_drive = nameinfo.drive; } // if second name does not have a drive, use drive from first, // but only if it is defined if (nameinfo.file[0].drive == NAMEINFO_UNUSED_DRIVE && nameinfo.drive != NAMEINFO_UNDEF_DRIVE) { nameinfo.file[0].drive = nameinfo.drive; } // here is the place to plug in other file system providers, // like SD-Card, or even an outgoing IEC or IEEE, to convert between // the two bus systems. This is done depending on the drive number // and managed with the ASSIGN call. //provider_t *provider = &serial_provider; endpoint_t *endpoint = NULL; if (type == FS_OPEN_DIRECT) { debug_printf("Getting direct endpoint provider for channel %d\n", channel_no); endpoint = direct_provider(); } else { endpoint = provider_lookup(nameinfo.drive, (char*) nameinfo.drivename); } // convert from bus' PETSCII to provider // currently only up to the first zero byte is converted, options like file type // are still ASCII only // in the future the bus may have an own conversion option... cconv_converter(CHARSET_PETSCII, endpoint->provider->charset(endpoint->provdata)) ((char*)nameinfo.name, strlen((char*)nameinfo.name), (char*)nameinfo.name, strlen((char*)nameinfo.name)); for (uint8_t i=0 ; i < nameinfo.num_files ; ++i) { if (nameinfo.file[i].name != NULL) { cconv_converter(CHARSET_PETSCII, endpoint->provider->charset(endpoint->provdata)) ((char*)nameinfo.file[i].name, strlen((char*)nameinfo.file[i].name), (char*)nameinfo.file[i].name, strlen((char*)nameinfo.file[i].name)); } } if (type == FS_MOVE && nameinfo.file[0].drive != NAMEINFO_UNUSED_DRIVE // then use ep from first drive anyway && nameinfo.file[0].drive != nameinfo.drive) { // no need to check if the same // two-name command(s) with possibly different drive numbers endpoint_t *endpoint2 = provider_lookup(nameinfo.file[0].drive, (char*) nameinfo.file[0].name); if (endpoint2 != endpoint) { debug_printf("ILLEGAL DRIVE COMBINATION: %d vs. %d\n", nameinfo.drive+0x30, nameinfo.file[0].drive+0x30); set_error_tsd(errormsg, CBM_ERROR_DRIVE_NOT_READY, 0, 0, nameinfo.drive); return -1; } } // check the validity of the drive (note that in general provider_lookup // returns a default provider - serial-over-USB to the PC, which then // may do further checks if (endpoint == NULL) { debug_puts("ILLEGAL DRIVE: "); debug_putc(0x30+nameinfo.drive); debug_putcrlf(); set_error_tsd(errormsg, CBM_ERROR_DRIVE_NOT_READY, 0, 0, nameinfo.drive); return -1; } provider_t *provider = endpoint->provider; // find open slot //int8_t slot = -1; open_t *activeslot = NULL; for (uint8_t i = 0; i < MAX_ACTIVE_OPEN; i++) { if (active[i].channel_no < 0) { //slot = i; activeslot = (open_t*) &active[i]; break; } } //if (slot < 0) { if (activeslot == NULL) { debug_puts("NO OPEN SLOT FOR OPEN!"); debug_putcrlf(); set_error_tsd(errormsg, CBM_ERROR_NO_CHANNEL, 0, 0, nameinfo.drive); return -1; } activeslot->endpoint = endpoint; uint8_t len = assemble_filename_packet(cmd_buffer, &nameinfo); #ifdef DEBUG_FILE debug_printf("LEN AFTER ASSEMBLE=%d\n", len); #endif packet_init(&activeslot->txbuf, len, cmd_buffer); // store pointer to runtime config in packet // used by providers running on the device activeslot->txbuf.rtc = rtconf; packet_set_filled(&activeslot->txbuf, channel_no, type, len); if (!iscmd) { // only for file opens // note: we need the provider for the dir converter, // so we can only do it in here. // open channel uint8_t writetype = WTYPE_READONLY; if (type == FS_OPEN_WR || type == FS_OPEN_AP || type == FS_OPEN_OW) { writetype = WTYPE_WRITEONLY; } else if (type == FS_OPEN_RW) { writetype = WTYPE_READWRITE; } if (nameinfo.options & NAMEOPT_NONBLOCKING) { writetype |= WTYPE_NONBLOCKING; } int8_t (*converter)(void *, packet_t*, uint8_t) = (type == FS_OPEN_DR) ? (provider->directory_converter) : NULL; // TODO: if provider->channel_* are not NULL, we should probably not allocate a channel // but that would break the FILE OPEN detection here. channel_t *channel = channel_find(channel_no); if (channel != NULL) { // clean up channel_close(channel_no); // Note: it seems possible to open the same channel multiple times // on a direct file if (type != FS_OPEN_DIRECT) { debug_puts("FILE OPEN ERROR"); debug_putcrlf(); set_error_tsd(errormsg, CBM_ERROR_NO_CHANNEL, 0, 0, nameinfo.drive); return -1; } } int8_t e = channel_open(channel_no, writetype, endpoint, converter, nameinfo.drive); if (e < 0) { debug_puts("E="); debug_puthex(e); debug_putcrlf(); set_error_tsd(errormsg, CBM_ERROR_NO_CHANNEL, 0, 0, nameinfo.drive); return -1; } } activeslot->callback = callback; // no more error here, just the submit. // so callers can be sure if this function returns <0, they do not need // to close the channel, as it has not been opened // If this function returns 0, a callback must be received and handled, // and the channel is already opened. activeslot->channel_no = channel_no; // prepare response buffer packet_init(&activeslot->rxbuf, OPEN_RX_DATA_LEN, activeslot->rxdata); provider->submit_call(endpoint->provdata, channel_no, &activeslot->txbuf, &activeslot->rxbuf, _file_open_callback); return 0; }