Я пишу команды на ленточный принтер, используя OpenNETCF.IO.Ports.SerialPort следующим образом:
public static bool SendCommandToPrinter(string cmd)
{
bool success; // init'd to false by default
try
{
SerialPort serialPort = new SerialPort();
serialPort.BaudRate = 19200;
serialPort.Handshake = Handshake.XOnXOff;
serialPort.Open();
serialPort.Write(cmd);
serialPort.Close();
success = true;
}
catch // may not need a try/catch block, as success defaults to false
{
success = false;
}
return success;
}
... теперь мне нужно прочитать значение, возвращаемое из вызова "get val", но я не знаю, как, и я не смог найти, как это сделать. У меня есть следующее начало, но не знаю, как "заполнить пробел":
string getDeviceLang = string.Format("! U1 getvar {0}device.languages{0}", quote);
public static string GetSettingFromPrinter(string cmd)
{
string settingVal = string.Empty;
SerialPort serialPort = new SerialPort();
serialPort.BaudRate = 19200;
serialPort.Handshake = Handshake.XOnXOff;
serialPort.Open();
serialPort.Write(cmd); // do I even need this call to write?
settingVal = serialPort.Read() // ???
serialPort.Close();
return settingVal;
}
Метод OpenNETCF.IO.Ports.SerialPort Read() принимает массив байтов ("буфер"), за которым следует int ("offset") и другой int ("count") и возвращает int. Я не знаю, что использовать в качестве аргументов или что делать с результатом int.
Я попробовал это:
public static string GetSettingFromPrinter(string cmd)
{
string settingVal = string.Empty;
try
{
SerialPort serialPort = new SerialPort();
serialPort.BaudRate = 19200;
serialPort.Handshake = Handshake.XOnXOff;
serialPort.Open();
serialPort.Write(cmd);
// testing...
settingVal = serialPort.ReadLine();
serialPort.Close();
return settingVal;
}
catch (Exception x)
{
MessageBox.Show(x.ToString());
return settingVal;
}
}
... но это вознаграждает меня менее чем удовлетворительным, "System.NotSupportedException: еще не в OpenNETCF.IP.Ports.SerialPort.ReadTo (значение строки) в..."
Я добавил:
serialPort.ReadTimeout = 500;// made no difference
Исходя из этого, я попытался заставить его работать так:
public class PrintUtils
{
static SerialPort _serialPort;
static bool keepReading = true;
static string settingVal = string.Empty;
. . .
public static string GetSettingFromPrinter(string cmd)
{
Thread readThread = new Thread(ReadSetting());
try
{
_serialPort = new SerialPort();
_serialPort.BaudRate = 19200;
_serialPort.Handshake = Handshake.XOnXOff;
_serialPort.Open();
while (keepReading)
{
_serialPort.WriteLine(cmd);
}
_serialPort.Close();
return settingVal;
}
catch (Exception x)
{
MessageBox.Show(x.ToString());
return settingVal;
}
}
public static void ReadSetting()
{
while (keepReading)
{
try
{
settingVal = _serialPort.ReadLine();
keepReading = settingVal.Equals(string.Empty);
}
catch (Exception ex) { MessageBox.Show(ex.ToString());}
}
}
... но я получаю "Метод" PDAClient.PrintUtils.Read(), на который ссылаются без круглых скобок "в этой строке:
Thread readThread = new Thread(Read);
Если я дам это parens:
Thread readThread = new Thread(ReadSetting());
... он говорит мне: "Аргумент" 1 ": невозможно преобразовать из" void "в System.Threading.ThreadStart"
-and:
"Наилучшее перегруженное соответствие метода для System.Threading.Thread.Thread(System.Threading.ThreadStart) имеет некоторые недопустимые аргументы"
И с помощью этого кода:
public static string GetSettingFromPrinter(string cmd)
{
string setting = string.Empty;
byte[] buffer = null;
try
{
SerialPort serialPort = new SerialPort();
serialPort = new SerialPort();
serialPort.BaudRate = 19200;
serialPort.Handshake = Handshake.XOnXOff;
serialPort.ReadTimeout = 500;
serialPort.Open();
serialPort.Write(cmd);
setting = Convert.ToString(serialPort.Read(buffer, 0, buffer.Length));
serialPort.Close();
return setting;
}
catch (Exception x)
{
MessageBox.Show(x.ToString());
return setting;
}
}
Я получаю NRE.
Эта попытка:
serialPort.WriteLine(cmd);
setting = serialPort.ReadExisting();
... заканчивается очень похоже на первое обновление ("System.NotSupportedException: еще не в OpenNETCF.IP.Ports.SerialPort.ReadExisting() at...")
Хорошо, я включил псевдокод в комментарий ctacke, и теперь у меня есть это:
const string quote = "\"";
. . .
string getDeviceLang = string.Format("! U1 getvar {0}device.languages{0}", quote);
. . .
String deviceLanguage = PrintUtils.GetSettingFromPrinter(getDeviceLang);
public static string GetSettingFromPrinter(string cmd)
{
string setting = string.Empty;
try
{
SerialPort serialPort = new SerialPort();
serialPort = new SerialPort();
serialPort.BaudRate = 19200;
serialPort.Handshake = Handshake.XOnXOff;
serialPort.ReadTimeout = 500;
serialPort.Open();
serialPort.WriteLine(cmd); // or Write()
// get a synchronous, newline-delimited response
StringBuilder response = new StringBuilder();
char c;
do
{
c = (char)serialPort.ReadByte();
response.Append(c);
} while(c != '\n');
serialPort.Close();
return setting;
}
catch (Exception x)
{
MessageBox.Show(x.ToString());
return setting;
}
... но он "висит" - кажется, существует бесконечный цикл в цикле do... while.
Я добавил это после "ReadByte":
MessageBox.Show(c.ToString());
... и все это показывает мне ничто (MessageBox без "внутреннего текста"); Я позволил ему появиться 32 раза, прежде чем я смонтировал устройство.
Хорошо, тогда я исправляюсь - я не использовал OpenNETCF SerialPort, поскольку такой вещи нет. Поэтому я пытаюсь это сделать, основываясь на предоставленном псевдокоде ctacke. Я сейчас пытаюсь использовать:
Port serialPort = new Port();
serialPort.Settings = whateverPortSettingsYouNeed;
serialPort.Open();
serialPort.Send(cmd);
... но я не знаю, что должно быть "anyPortSettingsYouNeed", нет метода "Отправить", и я не знаю, что использовать вместо ReadByte()
У меня есть это сейчас для настроек:
BasicPortSettings bps = new BasicPortSettings();
bps.BaudRate = 19200;
//bps.ByteSize = ?;
//bps.Parity = None;
//bps.StopBits = 1;
Port serialPort = new Port();
serialPort.Settings = bps;
... но, как вы можете видеть, я не знаю, какие значения должны быть.
Это компилирует:
public static string GetSettingFromPrinter(string cmd)
{
string setting = string.Empty;
try
{
BasicPortSettings bps = new BasicPortSettings();
bps.BaudRate = BaudRates.CBR_19200;
bps.Parity = OpenNETCF.IO.Serial.Parity.none;
bps.StopBits = OpenNETCF.IO.Serial.StopBits.one; //bps.StopBits.one;
Port serialPort = new Port("COM1:", bps);
byte[] outputBytes = System.Text.Encoding.ASCII.GetBytes(cmd);
serialPort.Output = outputBytes;
serialPort.Open();
byte[] bites = serialPort.Input;
setting = bites.ToString();
serialPort.Close();
return setting;
}
catch (Exception x)
{
MessageBox.Show(x.ToString());
return setting;
}
}
... Теперь я посмотрю, действительно ли это работает...
Я узнал (трудный путь), что мне пришлось открыть порт до установки Output val; это сейчас:
serialPort.Open();
byte[] outputBytes = Encoding.ASCII.GetBytes(cmd);
serialPort.Output = outputBytes;
byte[] inputBytes = serialPort.Input;
setting = inputBytes.ToString();
... но то, что читается в настройке, - "System.Byte []"
Что мне нужно, чтобы фактически получить значение в inputBytes, а не просто увидеть представление его типа?
Первое, что я замечаю, это то, что вы используете класс SerialPort
который означает, что вы используете код из SDF 1.x, который относится к 2005 году в самом последнем. Не уверен, что я был бы слишком восторжен по этому поводу. Я создал библиотеку с открытым исходным кодом, которая содержит только класс Port
после этого кода, но она работает иначе - она была смоделирована после объектной модели последовательного порта VB6. Я, честно говоря, даже не помню, кто написал код в SDF 1.x - возможно, был я, возможно, не был. Я думаю, что не просто судить по стилю кода, который я вижу.
Я задавался вопросом, почему вы не просто использовали встроенный файл CF-серий, но если вы используете SDF 1.x, скорее всего, вы используете версию CF, которая предваряет включение API последовательного порта.
Что касается того, который вы используете сейчас, я думаю, что это несколько зависит от того, как ожидается возвращение данных, но псевдокод будет выглядеть примерно так:
var port = new SerialPort;
port.Settings = whateverPortSettingsYouNeed;
port.Open();
....
// send the command
port.Send(myCommand);
// get a synchronous, newline-delimited response
var response = new StringBuilder();
char c;
do
{
c = (char)port.ReadByte();
// see if it actually read anything
if(c == '\0')
{
// wait a little bit, then try again - you will want to put in a timeout here
Thread.Sleep(10);
continue;
}
response.Append(c);
// you may want to check for response "reasonableness" here
} while(c != \n');
DoSomethingWithResponse(response);
Port
не SerialPort
. Он также не имеет методов Read()
или Write
. Основываясь на опубликованном вами коде, вы используете SerialPort
из SDF 1x, который представляет собой совершенно отдельную кодовую базу с совершенно другой объектной моделью и для которого предназначен вышеуказанный псевдокод (хотя обычно он работает с любой реализацией, поскольку псевдокод).
Он считывает байты. Буфер - это где байты считываются (как изменено смещением и количеством), а возвращаемое значение - количество прочитанных байтов. Типичный материал типа потока.
Документы находятся здесь: http://msdn.microsoft.com/en-us/library/ms143549(v=vs.90).aspx