#!/usr/bin/perl 

my $Version = "v20210315";

my @TwoTab = (0, 1, 2, 4, 8, 16, 32, 64, 128);

if( $ARGV[0] =~ /(CONF|INFO|HW)/i ) {
	if( scalar(@ARGV) == 1 ) {
		system( "i2c -w 67 0x30" );  # get system info
		my $cmd = `i2c -r 67 10`;
		my ($dmy, $firmwversh, $firmwversl, $hardwvers, $bootlmode, @dmy) = split( ' ', $cmd );
		print "  PIC24 (I/O processor)\n";
		print "      Firmware = v$firmwversh.$firmwversl\n";
		print "      Hardware = v$hardwvers\n";
		system( "i2c -w 67 0x02" );  # get hardware configuration
		$cmd = `i2c -r 67 4`;
		my ($dmy2, $hwconfig, $rxinfo, $txinfo) = split( ' ', $cmd );
		print "      current configuration = $hwconfig (hwconfig = x.$hwconfig.x.x)\n";
		my $rxdig = $TwoTab[($rxinfo & 0x03)];
		my $rxana = $TwoTab[($rxinfo & 0x1c) >> 2];
		my $rxkeyb = ($rxinfo & 0x20) >> 5;
		my $rxcntr = ($rxinfo & 0xc0) >> 6;
		printf "  OUTPUT (rxinfo byte = 0x%02x)\n", $rxinfo;
		print  "      digital      = $rxdig byte(s)\n";
		print  "      analog       = $rxana word(s)\n";
		print  "      keyb control = $rxkeyb word(s)\n";
		print  "      counter res  = $rxcntr word(s)\n";
		my $txdig = $TwoTab[($txinfo & 0x03)];
		my $txana = $TwoTab[($txinfo & 0x1c) >> 2];
		my $txkeyb = ($txinfo & 0x20) >> 5;
		my $txcntr = ($txinfo & 0xc0) >> 6;
		printf "  INPUT (txinfo byte = 0x%02x)\n", $txinfo;
		print  "      digital      = $txdig byte(s)\n";
		print  "      analog       = $txana word(s)\n";
		print  "      keyb status  = $txkeyb word(s)\n";
		print  "      counter ctrl = $txcntr word(s)\n";
	}
	elsif( scalar(@ARGV) == 2 ) {
		my $hwconfig = $ARGV[1];
		system( "i2c -w 67 0x01 $hwconfig" );  # set hardware configuration
	}
	else {
		print STDERR "error: only 1 argument expected\n";
	}
}

elsif( $ARGV[0] =~ /COM(\d)/i ) {
	my $comport = $1;
	if( scalar(@ARGV) == 1 ) {
		system( "i2c -w 67 0x21 $comport" );  # get uart configuration
		my $cmd = `i2c -r 67 10`;
		my ($dmy, $comidx, $intprot, $intbaud0, $intbaud1, $intbaud2, $extprot, $extbaud0, $extbaud1, $extbaud2 ) = split( ' ', $cmd );
		my $intbaud = $intbaud0 + ($intbaud1 << 8) + ($intbaud2 << 16);
		my $extbaud = $extbaud0 + ($extbaud1 << 8) + ($extbaud2 << 16);
		print "  COM$comidx (RS485):\n";
		print "    int = $intbaud ", Prot2txt($intprot), "\n";
		print "    ext = $extbaud ", Prot2txt($extprot), "\n";
	}
	elsif( scalar(@ARGV) == 3 || scalar(@ARGV) == 5 ) {
		if( scalar(@ARGV) == 3 ) {
			$intbaud = $ARGV[1];
			$intprot = Txt2prot($ARGV[2]);
			$extbaud = $ARGV[1];
			$extprot = Txt2prot($ARGV[2]);
		}
		else {  # scalar(@ARGV) == 5
			$intbaud = $ARGV[1];
			$intprot = Txt2prot($ARGV[2]);
			$extbaud = $ARGV[3];
			$extprot = Txt2prot($ARGV[4]);
		}
		$intbaud2 = ($intbaud >> 16) & 0xff;
		$intbaud1 = ($intbaud >> 8) & 0xff;
		$intbaud0 = ($intbaud & 0xff);
		$extbaud2 = ($extbaud >> 16) & 0xff;
		$extbaud1 = ($extbaud >> 8) & 0xff;
		$extbaud0 = ($extbaud & 0xff);
		system( "i2c -w 67 0x20 $comport $intprot $intbaud0 $intbaud1 $intbaud2 $extprot $extbaud0 $extbaud1 $extbaud2" );  # set uart configuration
	}
	else {
		print STDERR "error: wrong arguments\n";
	}
}

elsif( $ARGV[0] =~ /WD/i ) {
	if( scalar(@ARGV) == 1 ) {
		system( "i2c -w 67 0x32" );  # get watchdog status
		my $cmd = `i2c -r 67 2`;
		my ($dmy, $wdstate ) = split( ' ', $cmd );
		print "  Watchdog: $wdstate (", ($wdstate?"Active":"Off"), ")\n";
	}
	elsif( scalar(@ARGV) == 2 ) {
		my $wdstate = $ARGV[1] ? "1" : "0";
		system( "i2c -w 67 0x31 $wdstate" );  # set watchdog status
	}
	else {
		print STDERR "error: 1 argument expected\n";
	}
}

elsif( $ARGV[0] =~ /PWM/i ) {
	if( scalar(@ARGV) == 3 ) {
		my $idx = ReadHexDec( $ARGV[1] );
		if( $idx < 0 || $idx > 3 ) {
			print STDERR "error: idx must be in the range 0...3\n";
		}
		else {
			my $val = ReadHexDec( $ARGV[2] );
			system( "i2c -w 67 0x40 $idx ".($val & 0xff)." ".(($val >> 8) & 0xff) );  # set pwm frequency
		}
	}
	else {
		print STDERR "error: wrong arguments: expecting [idx val]\n";
	}
}

elsif( $ARGV[0] =~ /IN/i ) {
	system( "i2c -w 67 0x02" );  # get hardware configuration
	my $cmd = `i2c -r 67 4`;
	my ($dmy, $hwconfig, $rxinfo, $txinfo) = split( ' ', $cmd );
	my $reqlen = 2 + Info2len( $txinfo );
	system( "i2c -w 67 0x15" );  # get inputs
	$cmd = `i2c -r 67 $reqlen`;
	my @data = split( ' ', $cmd );
	if( $data[1] != $txinfo ) {
		chomp( $cmd );
		print STDERR "error: answer mismatch\n";
		print STDERR "(the reply sequence was: $cmd)\n";
	}
	else {
		my $dignum = $TwoTab[$txinfo & 0x03];
		my $ananum = $TwoTab[($txinfo & 0x1c) >> 2];
		my $keybnum = $TwoTab[($txinfo & 0x20) >> 5];
		if( $dignum + $ananum + $keybnum == 0 ) {
			chomp( $cmd );
			print "error: the current configuration has no inputs\n";
			print "(the reply sequence was: $cmd)\n";
		}
		else {
			my $mode = "dak";
			if( $ARGV[0] =~ /DIG/i ) {
				$mode = "d";
			}
			elsif( $ARGV[0] =~ /ANA/i ) {
				$mode = "a";
			}
			elsif( $ARGV[0] =~ /KEYB/i ) {
				$mode = "k";
			}
			if( $ARGV[1] =~ /CONF/i ) {  # channel config
				if( "$ARGV[2]" =~ /^POSS/i ) {  # possible
					print "  ch    cur   poss   (filter bits not displayed)\n";
					foreach my $ch ( 0..$ananum-1 ) {
						system( "i2c -w 67 0x07 $ch" );  # get possible configs
						$cmd = sprintf( "i2c -r 67 0x06" );
						$cmd = `$cmd`;
						my ($dmy, $curCfg, @possCfg) = split( ' ', $cmd );
						if( $dmy ne "0x07" ) {
							chomp( $cmd );
							print STDERR "error: answer mismatch\n";
							print STDERR "(the reply sequence was: $cmd)\n";
						}
						else {
							$curCfg = hex(substr($curCfg,2));
							$curCfg &= 0x3f;  # Filter-Bits ausblenden
							printf "  %2d    %-3d   ", $ch, $curCfg;
							foreach my $cfg ( @possCfg ) {
								$cfg = hex(substr($cfg,2));
								$cfg &= 0x3f;  # Filter-Bits ausblenden
								if( $cfg != 0 ) {
									printf "%-3d ", $cfg;
								}
								else {
									print "-   ";
								}
							}
							print "\n";
						}
					}
				}
				elsif( "$ARGV[2]" ne "" ) {  # set
					my $idx = 2;
					if( $mode =~ /d/ ) {
						$cmd = "i2c -w 67 0x03 0"; # set digin channel config
					}
					else {
						$cmd = "i2c -w 67 0x05 0"; # set anain channel config
					}
					while( "$ARGV[$idx]" ne "" ) {
						$cmd .= sprintf( " %d", ReadHexDec($ARGV[$idx]) );
						$idx ++;
					}
					system( $cmd );
				}
				else {  # get
					my $cmp;
					if( $mode =~ /d/ ) {
						$cmp = "0x04";
						system( "i2c -w 67 0x04 0" );  # get digin channel config
						$cmd = sprintf( "i2c -r 67 0x%x", $dignum*8+1 );
					}
					else {
						$cmp = "0x06";
						system( "i2c -w 67 0x06 0" );  # get anain channel config
						$cmd = sprintf( "i2c -r 67 0x%x", $ananum+1 );
					}
					$cmd = `$cmd`;
					my ($dmy, @data) = split( ' ', $cmd );
					if( $dmy ne $cmp ) {
						chomp( $cmd );
						print STDERR "error: answer mismatch\n";
						print STDERR "(the reply sequence was: $cmd)\n";
					}
					else {
						if( $mode =~ /d/ ) {
							print "  DIGIN config =";
						}
						else {
							print "  ANAIN config =";
						}
						foreach my $dat ( @data ) {
							print " $dat";
						}
						print "\n";
					}
				}
			}
			elsif( $ARGV[1] =~ /CAL/i ) {  # channel calibration
				if( "$ARGV[2]" ne "" ) {  # set
					my $idx = 2;
					$cmd = "i2c -w 67 0x1b 0"; # set anain channel calib
					while( "$ARGV[$idx]" ne "" ) {
						$cmd .= sprintf( " %d", ReadHexDec($ARGV[$idx]) );
						$idx ++;
					}
					system( $cmd );
				}
				else {  # get
					my $cmp;
					$cmp = "0x1c";
					system( "i2c -w 67 0x1c 0" );  # get anain channel calib
					$cmd = sprintf( "i2c -r 67 0x%x", $ananum+1 );
					$cmd = `$cmd`;
					my ($dmy, @data) = split( ' ', $cmd );
					if( $dmy ne $cmp ) {
						chomp( $cmd );
						print STDERR "error: answer mismatch\n";
						print STDERR "(the reply sequence was: $cmd)\n";
					}
					else {
						print "  ANAIN calib =";
						foreach my $dat ( @data ) {
							print " $dat";
						}
						print "\n";
					}
				}
			}
			else {  # Werte ausgeben
				my $idx = 2;
				if( $dignum > 0 ) {
					print "  IN digital =" if( $mode =~ /d/ );
					for( my $i=0; $i<$dignum; $i++ ) {
						printf " 0x%02X", $data[$idx] if( $mode =~ /d/ );
						$idx ++;
					}
					print "\n" if( $mode =~ /d/ );
				}
				if( $ananum > 0 ) {
					print "  IN analog =" if( $mode =~ /a/ );
					for( my $i=0; $i<$ananum; $i++ ) {
						my $val = $data[$idx] + ($data[$idx+1] << 8);
						#printf " 0x%04X", $val if( $mode =~ /a/ );
						if( $val > 32767 ) { $val = $val - 65536 }
						printf " %d", $val if( $mode =~ /a/ );
						$idx += 2;
					}
					print "\n" if( $mode =~ /a/ );
				}
				if( $keybnum > 0 ) {
					print "  IN keyboard status =" if( $mode =~ /k/ );
					printf " 0x%04X", $data[$idx] + ($data[$idx+1] << 8) if( $mode =~ /k/ );
					print "\n" if( $mode =~ /k/ );
				}
			}
		}
	}
}

elsif( $ARGV[0] =~ /OUT/i ) {
	if( scalar(@ARGV) > 1 ) {
		system( "i2c -w 67 0x02" );  # get hardware configuration
		my $cmd = `i2c -r 67 4`;
		my ($dmy, $hwconfig, $rxinfo, $txinfo) = split( ' ', $cmd );
		my $dignum = $TwoTab[$rxinfo & 0x03];
		my $ananum = $TwoTab[($rxinfo & 0x1c) >> 2];
		my $keybnum = $TwoTab[($rxinfo & 0x20) >> 5];
		if( $dignum + $ananum + $keybnum == 0 ) {
			chomp( $cmd );
			print STDERR "error: the current configuration has no outputs\n";
			print STDERR "(the reply sequence was: $cmd)\n";
		}
		else {
			if( $ARGV[1] =~ /CONF/i ) {
				if( "$ARGV[2]" =~ /^POSS/i ) {  # possible
					print "  ch    cur   poss   (filter bits not displayed)\n";
					foreach my $ch ( 0..$ananum-1 ) {
						system( "i2c -w 67 0x0e $ch" );  # get possible configs
						$cmd = sprintf( "i2c -r 67 0x04" );
						$cmd = `$cmd`;
						my ($dmy, $curCfg, @possCfg) = split( ' ', $cmd );
						if( $dmy ne "0x0e" ) {
							chomp( $cmd );
							print STDERR "error: answer mismatch\n";
							print STDERR "(the reply sequence was: $cmd)\n";
						}
						else {
							$curCfg = hex(substr($curCfg,2));
							$curCfg &= 0x3f;  # Filter-Bits ausblenden
							printf "  %2d    %-3d   ", $ch, $curCfg;
							foreach my $cfg ( @possCfg ) {
								$cfg = hex(substr($cfg,2));
								$cfg &= 0x3f;  # Filter-Bits ausblenden
								if( $cfg != 0 ) {
									printf "%-3d ", $cfg;
								}
								else {
									print "-   ";
								}
							}
							print "\n";
						}
					}
				}
				elsif( "$ARGV[2]" ne "" ) {  # set
					my $idx = 2;
					$cmd = "i2c -w 67 0x0b 0";
					while( "$ARGV[$idx]" ne "" ) {
						$cmd .= sprintf( " %d", ReadHexDec($ARGV[$idx]) );
						$idx ++;
					}
					system( $cmd );
				}
				else {  # get
					system( "i2c -w 67 0x0d 0" );  # get channel config
					$cmd = sprintf( "i2c -r 67 0x%x", $ananum+1 );
					$cmd = `$cmd`;
					my ($dmy, @data) = split( ' ', $cmd );
					if( $dmy ne "0x0d" ) {
						chomp( $cmd );
						print STDERR "error: answer mismatch\n";
						print STDERR "(the reply sequence was: $cmd)\n";
					}
					else {
						print "  ANAOUT config =";
						foreach my $dat ( @data ) {
							print " $dat";
						}
						print "\n";
					}
				}
			}
			elsif( $ARGV[1] =~ /CAL/i ) {
				if( "$ARGV[2]" ne "" ) {  # set
					my $idx = 2;
					$cmd = "i2c -w 67 0x17 0";  # set channel calib
					while( "$ARGV[$idx]" ne "" ) {
						$cmd .= sprintf( " %d", ReadHexDec($ARGV[$idx]) );
						$idx ++;
					}
					system( $cmd );
				}
				else {  # get
					system( "i2c -w 67 0x18 0" );  # get channel calib
					$cmd = sprintf( "i2c -r 67 0x%x", $ananum+1 );
					$cmd = `$cmd`;
					my ($dmy, @data) = split( ' ', $cmd );
					if( $dmy ne "0x18" ) {
						chomp( $cmd );
						print STDERR "error: answer mismatch\n";
						print STDERR "(the reply sequence was: $cmd)\n";
					}
					else {
						print "  ANAOUT calib =";
						foreach my $dat ( @data ) {
							print " $dat";
						}
						print "\n";
					}
				}
			}
			else {
				my $idx = 1;
				my $data = "";
				for( my $i=0; $i<$dignum; $i++ ) {
					if( "$ARGV[$idx]" ne "" ) {
						$data .= " $ARGV[$idx]";
					}
					$idx ++;
				}
				for( my $i=0; $i<$ananum; $i++ ) {
					if( "$ARGV[$idx]" ne "" ) {
						my $dat = ReadHexDec($ARGV[$idx]);
						$data .= " ".($dat & 0xff)." ".(($dat >> 8) & 0xff);
					}
					$idx ++;
				}
				for( my $i=0; $i<$keybnum; $i++ ) {
					if( "$ARGV[$idx]" ne "" ) {
						my $dat = ReadHexDec($ARGV[$idx]);
						$data .= " ".($dat & 0xff)." ".(($dat >> 8) & 0xff);
					}
					$idx ++;
				}
				if( "$ARGV[$idx]" ne "" ) {
					print STDERR "error: too many output values specified\n";
				}
				else {
					system( "i2c -w 67 0x14 $rxinfo $data" );  # set outputs
				}
			}
		}
	}
	else {
		system( "i2c -w 67 0x02" );  # get hardware configuration
		my $cmd = `i2c -r 67 4`;
		my ($dmy, $hwconfig, $rxinfo, $txinfo) = split( ' ', $cmd );
		my $reqlen = 2 + Info2len( $rxinfo );
		system( "i2c -w 67 0x16" );  # get outputs
		$cmd = `i2c -r 67 $reqlen`;
		my @data = split( ' ', $cmd );
		if( $data[1] != $rxinfo ) {
			chomp( $cmd );
			print STDERR "error: answer mismatch\n";
			print STDERR "(the reply sequence was: $cmd)\n";
		}
		else {
			my $dignum = $TwoTab[$rxinfo & 0x03];
			my $ananum = $TwoTab[($rxinfo & 0x1c) >> 2];
			my $keybnum = $TwoTab[($rxinfo & 0x20) >> 5];
			if( $dignum + $ananum + $keybnum == 0 ) {
				print STDERR "error: the current configuration has no outputs\n";
			}
			else {
				my $mode = "dak";
				if( $ARGV[0] =~ /DIG/i ) {
					$mode = "d";
				}
				elsif( $ARGV[0] =~ /ANA/i ) {
					$mode = "a";
				}
				elsif( $ARGV[0] =~ /KEYB/i ) {
					$mode = "k";
				}
				my $idx = 2;
				if( $dignum > 0 ) {
					print "  OUT digital =" if( $mode =~ /d/ );
					for( my $i=0; $i<$dignum; $i++ ) {
						printf " 0x%02X", $data[$idx] if( $mode =~ /d/ );
						$idx ++;
					}
					print "\n" if( $mode =~ /d/ );
				}
				if( $ananum > 0 ) {
					print "  OUT analog =" if( $mode =~ /a/ );
					for( my $i=0; $i<$ananum; $i++ ) {
						printf " 0x%04X", $data[$idx] + ($data[$idx+1] << 8) if( $mode =~ /a/ );
						$idx += 2;
					}
					print "\n" if( $mode =~ /a/ );
				}
				if( $keybnum > 0 ) {
					print "  OUT keyboard control =" if( $mode =~ /k/ );
					printf " 0x%04X", $data[$idx] + ($data[$idx+1] << 8) if( $mode =~ /k/ );
					print "\n" if( $mode =~ /k/ );
				}
			}
		}
	}
}

elsif( $ARGV[0] =~ /COUNT/i ) {
	system( "i2c -w 67 0x02" );  # get hardware configuration
	my $cmd = `i2c -r 67 4`;
	my ($dmy, $hwconfig, $rxinfo, $txinfo) = split( ' ', $cmd );
	my $counternum = $TwoTab[($rxinfo & 0xc0) >> 6];
	my $ch = $ARGV[1];
	my $num = $ARGV[2];
	if( $ARGV[0] =~ /COUNTERS/i ) {
		$ch = 'NUM';
		$num = $ARGV[1];
	}
	if( $ch =~ /NUM/i ) {
		if( $num =~ /^[0124]$/ ) {
			system( "i2c -w 67 0x60 $num" );  # set num counter
		}
		elsif( $num =~ /^\s*$/ ) {
			print "  COUNTER NUM = $counternum\n";
		}
		else {
			print STDERR "error: expecting NUM 0/1/2/4\n";
		}
	}
	elsif( $ch =~ /^(0x)?(\d+)$/ ) {
		my $hexout = 0;
		if( $1 eq '0x' ) {
			$ch = hex($2);
			$hexout = 1;
		}
		if( $ch >= $counternum ) {
			print STDERR "error: only $counternum counters available\n";
		}
		else {
			my $regcmd = $ARGV[2];
			my $arg = $ARGV[3];
			if( $arg =~ /^\s*$/ ) {  # get register
				my $reg;
				if( $regcmd =~ /^\s*$/i || $regcmd =~ /RESULT/ ) {
					$regcmd = 'RESULT';
					$reg = 0x64;
				}
				elsif( $regcmd =~ /CTRL/i ) {
					$regcmd = 'CTRL';
					$reg = 0x63;
				}
				elsif( $regcmd =~ /CFG|BITS/i ) {
					$regcmd = 'CFGBITS';
					$reg = 0x66;
				}
				elsif( $regcmd =~ /PRESET|GATE/i ) {
					$regcmd = 'PRESET';
					$reg = 0x68;
				}
				else {
					print STDERR "error: unknown counter register $regcmd\n";
				}
				system( "i2c -w 67 $reg $ch" );
				my $cmd = `i2c -r 67 4`;
				my ($dmy, $ch, @data) = split( ' ', $cmd );
				my $val = ($data[0] + ($data[1] << 8));
				if( $hexout ) {
					print "  COUNTER[$ch] ", uc($regcmd), " = ", sprintf("0x%04x",$val), "\n";
				}
				else {
					print "  COUNTER[$ch] ", uc($regcmd), " = $val\n";
				}
			}
			else {  # set register
				$arg = ReadHexDec( $arg );
				my $reg;
				if( $regcmd =~ /CTRL/i ) {
					$regcmd = 'CTRL';
					$reg = 0x62;
				}
				elsif( $regcmd =~ /CFG|BITS/i ) {
					$regcmd = 'CFGBITS';
					$reg = 0x65;
				}
				elsif( $regcmd =~ /PRESET|GATE/i ) {
					$regcmd = 'PRESET';
					$reg = 0x67;
				}
				else {
					print STDERR "error: unknown counter register $regcmd\n";
				}
				my $data .= " ".($arg & 0xff)." ".(($arg >> 8) & 0xff);
				system( "i2c -w 67 $reg $ch $data" );
			}
		}
	}
	else {
		print STDERR "error: expecting NUM or channel index 0...3\n";
	}
}

else {
	my $myself = $0;
	$myself =~ s{.*/}{};
	print STDERR << "EOF";
  $0 $Version
  
  Configuration commands:
    $myself CONF                         - show configuration and PIC24 info
    $myself CONF conf                    - set configuration
	
  Digital I/O commands:
    $myself IN                           - show all input values
    $myself DIGIN                        - show digital input values
    $myself DIGIN CONF                   - show digital input configuration
    $myself DIGIN CONF cfg0 [cfg1]       - set digital input configuration
    $myself KEYBIN                       - show keyboard input status values
    $myself OUT                          - show current output values
    $myself OUT dat0 [dat1...]           - set output values

  Analog input commands:
    $myself ANAIN                        - show analog input values
    $myself ANAIN CONF                   - show analog input configuration
    $myself ANAIN CONF cfg0 [cfg1]       - set analog input configuration
    $myself ANAIN CONF POSSIBLE          - show possible analog input configurations
    $myself ANAIN CAL                    - show analog input calibration mode
    $myself ANAIN CAL cal0 [cal1]        - set analog input calibration mode
	
  Analog output commands:
    $myself ANAOUT                       - show analog output values
    $myself ANAOUT CONF                  - show analog output configuration
    $myself ANAOUT CONF cfg0 [cfg1]      - set analog output configuration
    $myself ANAOUT CONF POSSIBLE         - show possible analog output configurations
    $myself ANAOUT CAL                   - show analog output calibration mode
    $myself ANAOUT CAL cal0 [cal1]       - set analog output calibration mode
	
  UART commands:
    $myself COMn                         - show uart parameters
    $myself COMn baud prot               - set uart parameters int. and ext.
    $myself COMn baudi proti baude prote - set uart parameters int. and ext.
	
  Watchdog commands:
    $myself WD                           - show watchdog state
    $myself WD 1/0                       - enable/disable watchdog

  Counter commands:
    $myself COUNTER NUM [num]            - get/set number of counters
    $myself COUNTER idx                  - show counter[idx] result
    $myself COUNTER idx CTRL [val]       - get/set counter[idx] control
    $myself COUNTER idx CFGBITS [val]    - get/set counter[idx] config bits
    $myself COUNTER idx PRESET [val]     - get/set counter[idx] preset val

  PWM commands:
    $myself PWM idx val                  - set pwm frequency[idx]

  For the RTC features of the PIC24, use the /sbin/rtc utility.
EOF
}


sub Prot2txt
{
	my $prot = shift;
	my %numdatatab = ( 0=>7, 1=>8, 2=>9 );
	my $numdata = $numdatatab{$prot & 0x03};
	my %paritytab = ( 0=>"N", 1=>"E", 2=>"O" );
	my $parity = $paritytab{($prot & 0x0c) >> 2};
	my %numstoptab = ( 0=>1, 1=>2 );
	my $numstop = $numstoptab{($prot & 0x10) >> 4};
	return "$numdata$parity$numstop";
}

sub Txt2prot
{
	my $txt = shift;
	$txt =~ /.*([789]).*([neo]).*([12])/i;
	my %numdatatab = ( 7=>0, 8=>1, 9=>2 );
	my $numdata = $numdatatab{"$1"};
	my %paritytab = ( n=>0, e=>1, o=>2 );
	my $parity = $paritytab{lc($2)};
	my %numstoptab = ( 1=>0, 2=>1 );
	my $numstop = $numstoptab{$3};
	return ($numstop << 4) | ($parity << 2) | $numdata;
}

sub Info2len
{
	my $infobyte = shift;
	my $len = $TwoTab[$infobyte & 0x03];  # dig in
	$len += 2 * $TwoTab[($infobyte & 0x1c) >> 2];  # ana in
	$len += 2 * (($infobyte & 0x20) >> 5);  # keyb status
	$len += 2 * (($infobyte & 0xc0) >> 6);  # counter
	return $len;
}

sub ReadHexDec
{
	my $dat = shift;
	
	if( $dat =~ /^0x(.*)/i ) {
		return hex($1);
	}
	return $dat;
}
