1
0
mirror of https://github.com/UzixLS/ehs5fs.git synced 2025-07-18 14:51:20 +03:00
Files
ehs5fs/modem.c
2015-09-21 10:11:42 +03:00

355 lines
10 KiB
C

#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <termios.h>
#include <time.h>
#include <unistd.h>
#include "modem.h"
static int call(
struct modem *m,
const char *cmd,
unsigned cmdlen,
char *retbuf,
unsigned retmaxbytes,
unsigned *retbytes )
{
#define call_checkstr(str, retcode) \
if( bytes >= sizeof(str)-1 && strncmp( &(retbuf[bytes-sizeof(str)+1]), str, sizeof(str)-1 ) == 0 ) { \
ret = retcode; \
bytes -= sizeof(str)-1; \
break; \
}
unsigned bytes = 0;
int ret = 0;
if( m == NULL || cmd == NULL ) return -1;
if( cmdlen == 0 ){
printf( "call write [[[%s]]]\n", cmd );
cmdlen = strlen( cmd );
} else {
printf( "call write %u raw bytes\n", cmdlen );
}
tcflush( m->fd, TCIOFLUSH );
while( cmdlen-- ) {
if( write( m->fd, cmd, 1 ) != 1 ) {
perror( "call write error" );
return -1;
}
cmd++;
}
fsync( m->fd );
if( retmaxbytes < 1 || retbuf == NULL ) return 0;
while( bytes < retmaxbytes ) {
if( read( m->fd, &(retbuf[bytes]), 1 ) != 1 ) break;
bytes++;
call_checkstr( "\r\nOK\r\n", 1 );
call_checkstr( "\r\nERROR\r\n", -2 );
call_checkstr( "\r\nCONNECT\r\n", 1 );
}
retbuf[bytes] = 0;
if( retbytes != NULL ) *retbytes = bytes;
printf( "call read %d bytes (from %d) ret=%d [[[%s]]]\n", bytes, retmaxbytes, ret, retbuf );
return ret;
}
int m_ls( struct modem *m, const char *path, void *fusebuf, fuse_fill_dir_t fusefiller )
{
char buf[1024], scanbuf[128];
char *bufptr = buf;
if( m == NULL || path == NULL || fusebuf == NULL || fusefiller == NULL ) return -1;
snprintf( buf, sizeof(buf)-1, "AT^SFSA=\"ls\",\"a:/%s\"\r\n", path );
if( call( m, buf, 0, buf, sizeof(buf), NULL ) <= 0 ) return -1;
while( 1 ) {
strsep( &bufptr, "\n" );
if( bufptr == NULL ) break;
scanbuf[0] = 0;
if( sscanf( bufptr, "^SFSA: \"%s\"\r\n", scanbuf ) != 1) continue;
if( strlen( scanbuf ) < 2 ) continue;
scanbuf[strlen(scanbuf)-1] = 0;
if( scanbuf[strlen(scanbuf)-1] == '/' )
scanbuf[strlen(scanbuf)-1] = 0;
if( fusebuf != NULL && fusefiller != NULL )
fusefiller( fusebuf, scanbuf, NULL, 0 );
}
return 0;
}
int m_stat( struct modem *m, const char *path, struct stat *fusest )
{
char buf[1024];
char *bufptr = buf;
if( m == NULL || path == NULL || fusest == NULL ) return -1;
snprintf( buf, sizeof(buf)-1, "AT^SFSA=\"stat\",\"a:/%s\"\r\n", path );
if( call( m, buf, 0, buf, sizeof(buf), NULL ) <= 0 ) {
int errcode;
strsep( &bufptr, "\n" );
if( bufptr == NULL ) return -1;
if( sscanf( bufptr, "^SFSA: %d\r\n", &errcode ) != 1 ) return -1;
printf( "m_stat errcode %d\n", errcode );
switch( errcode ) {
case RESULT_NOTFOUND:
return ENOENT;
default:
return EIO;
}
}
for( int i = 0; i < 6; i++ ) {
int tmp;
struct tm tp;
strsep( &bufptr, "\n" );
if( bufptr == NULL ) return -3;
switch( i ) {
case 1:
case 2:
case 3:
if( sscanf( bufptr, "^SFSA: \"%d/%d/%d,%d:%d:%d\"\r\n",
&(tp.tm_year), &(tp.tm_mon), &(tp.tm_mday),
&(tp.tm_hour), &(tp.tm_min), &(tp.tm_sec) ) != 6 ) return -4-i;
tp.tm_year += 100;
}
switch( i ) {
case 0:
if( sscanf( bufptr, "^SFSA: %d\r\n", &tmp ) != 1 ) return -4;
fusest->st_size = tmp;
break;
case 1:
fusest->st_atim.tv_sec = mktime( &tp );
break;
case 2:
fusest->st_mtim.tv_sec = mktime( &tp );
break;
case 3:
fusest->st_ctim.tv_sec = mktime( &tp );
break;
case 4:
if( sscanf( bufptr, "^SFSA: %d\r\n", &tmp ) != 1 ) return -8;
if( tmp == ATTR_FILE )
fusest->st_mode = S_IFREG | 0666;
else
fusest->st_mode = S_IFDIR | 0777;
break;
}
}
return 0;
}
int m_read( struct modem *m, int fh, unsigned size, char *outbuf )
{
char buf[MAX_SIZE+100];
char *bufptr = buf;
if ( m == NULL ) return -1;
printf( "m_read %d (%u)\n", fh, size );
snprintf( buf, sizeof(buf)-1, "AT^SFSA=\"read\",%d,%u\r\n", fh, size );
if( call( m, buf, 0, buf, sizeof(buf), NULL ) <= 0 ) return -2;
strsep( &bufptr, "\n" );
strsep( &bufptr, "\n" );
if( bufptr == NULL ) return -3;
if( outbuf != NULL )
memcpy( outbuf, bufptr, size );
return 0;
}
int m_seek( struct modem *m, int fh, int offset, enum seek flags )
{
char buf[100];
if( m == NULL ) return -1;
printf( "m_seek %d to %d\n", fh, offset );
snprintf( buf, sizeof(buf)-1, "AT^SFSA=\"seek\",%d,%d,%d\r\n", fh, offset, flags );
if( call( m, buf, 0, buf, sizeof(buf), NULL ) <= 0 ) return -2;
return 0;
}
int m_open( struct modem *m, const char *path, enum flags flags )
{
int fh = -1;
char buf[100];
char *bufptr = buf;
if( m == NULL || path == NULL ) return -1;
printf( "m_open %s\n", path );
snprintf( buf, sizeof(buf)-1, "AT^SFSA=\"open\",\"a:/%s\",%u\r\n", path, flags );
if( call( m, buf, 0, buf, sizeof(buf), NULL ) <= 0 ) return -1;
strsep( &bufptr, "\n" );
if( bufptr == NULL ) return -2;
if( sscanf( bufptr, "^SFSA: %d,0\r\n", &fh ) != 1 ) {
printf( "m_open sscanf failed\n" );
return -3;
}
printf( "m_open ret %d\n", fh );
return fh;
}
int m_close( struct modem *m, int fh )
{
char buf[100];
if( m == NULL ) return -1;
printf( "m_close #%d\n", fh );
snprintf( buf, sizeof(buf)-1, "AT^SFSA=\"close\",%d\r\n", fh );
if( call( m, buf, 0, buf, sizeof(buf), NULL ) <= 0 ) return -2;
return 0;
}
int m_write( struct modem *m, int fh, unsigned size, const char *data )
{
char buf[size+100];
if( m == NULL || data == NULL ) return -1;
printf( "m_write %u bytes to #%d\n", size, fh );
snprintf( buf, sizeof(buf)-1, "AT^SFSA=\"write\",%d,%u\r\n", fh, size );
if( call( m, buf, 0, buf, sizeof(buf), NULL ) < 0 ) return -2;
if( call( m, data, size, buf, size, NULL ) < 0 ) return -3;
return (int)size;
}
int m_remove( struct modem *m, const char *path )
{
char buf[100];
if( m == NULL || path == NULL ) return -1;
printf( "m_remove %s\n", path );
snprintf( buf, sizeof(buf)-1, "AT^SFSA=\"remove\",\"a:/%s\"\r\n", path );
if( call( m, buf, 0, buf, sizeof(buf), NULL ) <= 0 ) return -1;
return 0;
}
int m_mkdir( struct modem *m, const char *path )
{
char buf[100];
if( m == NULL || path == NULL ) return -1;
printf( "m_mkdir %s\n", path );
snprintf( buf, sizeof(buf)-1, "AT^SFSA=\"mkdir\",\"a:/%s\"\r\n", path );
if( call( m, buf, 0, buf, sizeof(buf), NULL ) <= 0 ) return -1;
return 0;
}
int m_rmdir( struct modem *m, const char *path )
{
char buf[100];
if( m == NULL || path == NULL ) return -1;
printf( "m_rmdir %s\n", path );
snprintf( buf, sizeof(buf)-1, "AT^SFSA=\"rmdir\",\"a:/%s\"\r\n", path );
if( call( m, buf, 0, buf, sizeof(buf), NULL ) <= 0 ) return -1;
return 0;
}
int m_copy( struct modem *m, const char *srcpath, const char *dstpath )
{
char buf[100];
if( m == NULL || srcpath == NULL || dstpath == NULL ) return -1;
printf( "m_copy %s to %s\n", srcpath, dstpath );
snprintf( buf, sizeof(buf)-1, "AT^SFSA=\"copy\",\"a:/%s\",\"a:/%s\"\r\n", srcpath, dstpath );
if( call( m, buf, 0, buf, sizeof(buf), NULL ) <= 0 ) return -1;
return 0;
}
int m_rename( struct modem *m, const char *path, const char *newname )
{
char buf[100];
if( m == NULL || path == NULL || newname == NULL ) return -1;
printf( "m_rename %s to %s\n", path, newname );
snprintf( buf, sizeof(buf)-1, "AT^SFSA=\"rename\",\"a:/%s\",\"%s\"\r\n", path, newname );
if( call( m, buf, 0, buf, sizeof(buf), NULL ) <= 0 ) return -1;
return 0;
}
int m_gstat( struct modem *modem, struct statvfs *st )
{
char buf[200];
char *bufptr = buf;
if( modem == NULL || st == NULL ) return -1;
printf( "m_gstat\n" );
if( call( modem, "AT^SFSA=\"gstat\"\r\n", 0, buf, sizeof(buf), NULL ) <= 0 ) return -1;
for( int i = 0; i < 2; i++ ) {
unsigned tmp;
strsep( &bufptr, "\n" );
if( bufptr == NULL ) return -2;
switch( i ) {
case 0:
if( sscanf( bufptr, "^SFSA: %u\r\n", &tmp ) != 1) return -3;
st->f_blocks = tmp;
break;
case 1:
if( sscanf( bufptr, "^SFSA: %u\r\n", &tmp ) != 1) return -4;
st->f_bfree = tmp;
st->f_bavail = tmp;
break;
}
}
st->f_bsize = 1;
st->f_namemax = 64;
return 0;
}
int m_init( struct modem *m, const char *tty )
{
char buf[100];
if ( m == NULL )
return -1;
if ( (m->fd = open(tty, O_RDWR | O_NOCTTY | O_SYNC)) == -1 ) {
perror( "m_init: cannot open device" );
return -1;
}
tcgetattr( m->fd, &(m->termios) );
cfmakeraw( &(m->termios) );
m->termios.c_cc[VTIME] = 50;
m->termios.c_cc[VMIN] = 0;
/* set baud rates */
cfsetispeed( &(m->termios), B115200 );
cfsetospeed( &(m->termios), B115200 );
/* enable the receiver and set local mode */
m->termios.c_cflag |= (CLOCAL | CREAD);
/* set no parity, stop bits, data bits */
m->termios.c_cflag &= ~(unsigned)PARENB;
m->termios.c_cflag &= ~(unsigned)CSTOPB;
/* set character size as 8 bits */
m->termios.c_cflag &= ~(unsigned)CSIZE;
m->termios.c_cflag |= CS8;
/* Raw input mode, sends the raw and unprocessed data ( send as it is) */
m->termios.c_lflag &= ~(unsigned)(ICANON | ECHO | ISIG);
/* Raw output mode, sends the raw and unprocessed data ( send as it is). */
m->termios.c_oflag = ~(unsigned)OPOST;
tcflush( m->fd, TCOFLUSH );
tcsetattr( m->fd, TCSANOW, &(m->termios) );
if( call( m, "ATE0\r\n", 0, buf, sizeof(buf), NULL ) <= 0 )
return -1;
return 0;
}
int m_deinit( struct modem *m )
{
close( m->fd );
return 0;
}