Как я могу прочитать строку из OpenNETCF.IO.Ports.SerialPort?

Я пишу команды на ленточный принтер с помощью 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.

ОБНОВИТЬ

Я пробовал это:

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(строковое значение) в..."

ОБНОВЛЕНИЕ 2

Я добавил это:

serialPort.ReadTimeout = 500;// made no difference

ОБНОВЛЕНИЕ 3

На основании этого я попытался заставить его работать следующим образом:

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);

Если я делаю ставлю скобки:

Thread readThread = new Thread(ReadSetting());

... он говорит мне: "Аргумент '1': невозможно преобразовать 'void' в System.Threading.ThreadStart'"

-а также:

"Наилучшее совпадение перегруженного метода для System.Threading.Thread.Thread(System.Threading.ThreadStart)' содержит недопустимые аргументы"

ОБНОВЛЕНИЕ 4

И с этим кодом:

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.

ОБНОВЛЕНИЕ 5

Эта попытка:

serialPort.WriteLine(cmd);
setting = serialPort.ReadExisting();

... заканчивается очень похоже на первое обновление ("System.NotSupportedException: еще не в OpenNETCF.IP.Ports.SerialPort.ReadExisting() в...")

ОБНОВЛЕНИЕ 6

Хорошо, я включил псевдокод в комментарий 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 есть бесконечный цикл.

ОБНОВЛЕНИЕ 7

Я добавил это после "ReadByte":

MessageBox.Show(c.ToString());

... и все, что он мне показывает, это ничего (MessageBox без «внутреннего текста»); Я позволил ему появиться 32 раза, прежде чем я загрузил устройство.

ОБНОВЛЕНИЕ 8

Хорошо, тогда я исправлен - я не использовал последовательный порт OpenNETCF, так как его не существует. Итак, я пытаюсь получить это, основываясь на предоставленном псевдокоде. Я сейчас пытаюсь использовать:

Port serialPort = new Port();
serialPort.Settings = whateverPortSettingsYouNeed;
serialPort.Open();
serialPort.Send(cmd);

... но я не знаю, каким должен быть "whateverPortSettingsYouNeed", метода "Send" нет, и я не знаю, что использовать вместо ReadByte()

ОБНОВЛЕНИЕ 9

У меня это сейчас для настроек:

BasicPortSettings bps = new BasicPortSettings();
bps.BaudRate = 19200;
//bps.ByteSize = ?;
//bps.Parity = None;
//bps.StopBits = 1;
Port serialPort = new Port();
serialPort.Settings = bps;

... но, как видите, я не знаю, какими должны быть большинство значений.

ОБНОВЛЕНИЕ 10

Это компилирует:

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;
    }
}

...Теперь я посмотрю, действительно ли это работает...

ОБНОВЛЕНИЕ 11

Я узнал (трудным путем), что мне нужно было открыть порт перед установкой выходного значения; это снег:

serialPort.Open();
byte[] outputBytes = Encoding.ASCII.GetBytes(cmd);
serialPort.Output = outputBytes;
byte[] inputBytes = serialPort.Input;
setting = inputBytes.ToString();

... но в настройках читается "System.Byte[]"

Что мне нужно, чтобы на самом деле получить значение в inputBytes, а не просто увидеть представление его типа?


person B. Clay Shannon    schedule 10.06.2014    source источник
comment
Поскольку вы изменили библиотеки, весь ваш предыдущий код становится спорным. Настройки только вы бы знали, но это выглядит как 19200, без четности, 1 стоповый бит и т.д. Чтобы отправить данные, поместите их в свойство Output. Чтобы прочитать данные, прочтите свойство Input.   -  person ctacke    schedule 11.06.2014
comment
Хорошо, я попробую.   -  person B. Clay Shannon    schedule 11.06.2014
comment
Как установить для четности значение «Нет» или «Нет»? Эти значения не принимаются. Это перечисление? Кроме того, BaudRate не принимает int...?   -  person B. Clay Shannon    schedule 11.06.2014
comment
Хорошо, я получил эту часть: bps.BaudRate = BaudRates.CBR_19200;   -  person B. Clay Shannon    schedule 11.06.2014
comment
Аналогично для bps.StopBits = bps.StopBits.one; а как насчет отправки данных через свойство Output? Это назначается перед вызовом Open, а затем при вызове Open отправляется? Нитки не занимает...   -  person B. Clay Shannon    schedule 11.06.2014
comment
Чтобы преобразовать массив byte в массив String и обратно, используйте класс System.Text.Encoding. Так что используйте setting = Encoding.ASCII.GetString(inputBytes);   -  person tcarvin    schedule 12.06.2014


Ответы (2)


Первое, что я заметил, это то, что вы используете класс с именем 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);
person ctacke    schedule 11.06.2014
comment
Я я использую библиотеку OpenNETCF - это SerialPort, который я использую. - person B. Clay Shannon; 11.06.2014
comment
Я не согласен. В последовательной библиотеке Codeplex есть класс с именем Port, а не SerialPort. У него также нет методов Read() или Write. Основываясь на опубликованном вами коде, вы используете SerialPort из SDF 1x, который представляет собой совершенно отдельную базу кода с совершенно другой объектной моделью, и для которого предназначен приведенный выше псевдокод (хотя он обычно работает с любой реализацией, поскольку он псевдокод). - person ctacke; 11.06.2014
comment
Хорошо, я исправлен; Я думал, что использую OpenNETCF, и я за что-то в этом модуле, потому что его использование не выделено серым цветом... см. Обновление 8. - person B. Clay Shannon; 11.06.2014
comment
Строго говоря, оба являются OpenNETCF, поскольку мы написали и опубликовали оба, и у обоих есть наше пространство имен. Они просто разные. Это как с FTP, у нас есть две совершенно разные библиотеки с разной объектной моделью, но обе они наши. - person ctacke; 11.06.2014

Он читает байты. Буфер — это место, куда считываются байты (измененные смещением и количеством), а возвращаемое значение — это количество прочитанных байтов. Типичный материал потокового типа.

Документы находятся здесь: http://msdn.microsoft.com/en-us/library/ms143549%28v=vs.90%29.aspx

person tcarvin    schedule 10.06.2014
comment
Эти документы не относятся к SerialPort OpenNETCF, у которого, похоже, нет никаких документов. Его можно использовать таким же образом, но у него нет примера кода, только теория. - person B. Clay Shannon; 10.06.2014
comment
Ах я вижу. Не заметил, что вы использовали Opennet CF. Я почти уверен, что они следуют одному и тому же соглашению API. - person tcarvin; 10.06.2014
comment
Правильно, он следует стандартным соглашениям о потоках. - person ctacke; 11.06.2014