ESP-iDF | input from keyboard inside a task - esp32

How to take input from keyboard inside a task in ESP-IDF ,
The code I have tried is
void xTask1(void *params)
{
while (true)
{
char c = 0;
char str[4];
memset(str, 0, sizeof(str));
while (c != '\n')
{
printf("Enter the value:\n");
c = getchar();
if (c != 0xff)
{
str[strlen(str)] = c;
printf("%c", c);
}
vTaskDelay(100 / portTICK_PERIOD_MS);
}
int d = atoi(str);
printf("you have typed : %d\n", d);
}
}
void app_main(void)
{
xTaskCreate(xTask1, "task1", 2048, NULL, 1, NULL);
}
and the output I am getting is
I (309) cpu_start: Starting scheduler on PRO CPU.
I (0) cpu_start: Starting scheduler on APP CPU.
Enter the value:
Enter the value:
Enter the value:
Enter the value:
Enter the value:
Enter the value:
Enter the value:
Enter the value:
Enter the value:
Its not holding in to enter the input,
What is the mistake I am making here.?

Related

Menu type display in LCD using 4x4 Keypad in Arduino

I am trying to display two menu type in 16x2 LCD display using keypad in Arduino.
Here is the code;
`#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <Keypad.h>
byte rowPins[4]={9,8,7,6};
byte colPins [4]={5,4,3,2};
char keys[4][4]={
{'1','2','3','A'},
{'4','5','6','B'},
{'7','8','9','C'},
{'*','0','#','D'}
};
Keypad keypad = Keypad(makeKeymap(keys),rowPins,colPins,4,4);
LiquidCrystal_I2C lcd(0x27,16,2);
boolean present = false;
boolean next = false;
boolean final = false;
String num1, num2; //
float ans;//
char op;//
//String Line1 = " ";
//String Line2 = " ";
//char cursors = 0;
//
////phaseshift
//char phase_value[2];
//int phase_cursor;
//int phase_index;
//char phasesign;
//
////declare function
//void Phaseshift_Fn();
//void CV_Fn();
//void CC_Fn();
//void Remote_Fn();
void setup() {
lcd.init();
lcd.backlight();
lcd.begin (16,2);
lcd.clear();
lcd.setCursor(0, 0); lcd.print(Line1);
lcd.setCursor(0, 1); lcd.print(Line2);
delay(100);
lcd.setCursor(5,0);
lcd.print("HELLO");
lcd.setCursor(0,1);
lcd.print("PRESS FWD Button");
delay(2000);
lcd.clear();
delay(1000);
}
void loop() {
char key = keypad.getKey();
if(key == 'B'){
lcd.setCursor(0,0);
lcd.print("IF NO AIR BUBBLE");
lcd.setCursor(0,1);
lcd.print("PRESS STOP");
}
if(key == 'A'){
lcd.clear();
lcd.setCursor(0,0);
lcd.print("PRESS MODE");
lcd.setCursor(0,1);
switch(mode)
{
case Startup:
lcd.begin(16,2);
lcd.clear();
lcd.setCursor(0,0);
Line1 = "Enter Amount";
lcd.print(Line1);
lcd.setCursor(0,1);
Line2 = "Enter Time";
lcd.print(Line2);
delay(1000);
mode = Mainmenu;
break;
}
if (key != NO_KEY && (key=='1'||key=='2'||key=='3'||key=='4'||key=='5'||key=='6'||key=='7'||key=='8'||key=='9'||key=='0'))
{
if (present != true)
{
num1 = num1 + key; // storing the value of key pressed in num1
float numLength = num1.length();
lcd.setCursor(0, 1); /* decaling the place where the first entry will be displayed*/
lcd.print(num1); // printing the first number entered
}
else
{
num2 = num2 + key;//storing the value of second key pressed in num2
float numLength = num2.length();
lcd.setCursor(4, 1);/*decaling the place where the second entry will be displayed*/
lcd.print(num2); //printing the second number entered
final = true;
}
}
}`
As a beginner of the Arduino programming I tried so many methods including switch methods also.
But it didn't display. Please anyone can help me to solve this code?
I am trying to display this;enter image description here
Here I want to display
when I click the S button there two menus are displaying. They are Stop and Start. I want to display that two in LCD and if start button click then machine is forward after that when I click the stop button it should be stopped.

Flutter platform channels pass "multi-data" to windows function

I am testing the Platform-Channels with the windows visual studio 2022.
I can pass the single value from the flutter UI while I get the battery value, but I want to send multi-data from flutter to the windows code.
Here is mine test code which I follow the flutter tutorial:
class _MyHomePageState extends State<MyHomePage> {
static const MethodChannel platform =
MethodChannel('samples.flutter.dev/battery');
String _batteryLevel = 'Unknown battery level.';
int value = 100;
Future<void> _getBatteryLevel(int fluval) async {
String batteryLevel;
try {
final int result = await platform.invokeMethod('getBatteryLevel', fluval);
batteryLevel = 'Battery level at $result % .';
} on PlatformException catch (e) {
batteryLevel = "Failed to get battery level: '${e.message}'.";
}
setState(() {
_batteryLevel = batteryLevel;
});
}
#override
Widget build(BuildContext context) {
return Material(
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
ElevatedButton(
onPressed: () {
_getBatteryLevel(100);
},
child: const Text('Get Battery Level'),
),
Text(_batteryLevel),
],
),
),
);
}
}
and the windows side:
void initMethodChannel(flutter::FlutterEngine* flutter_instance) {
const static std::string channel_name("samples.flutter.dev/battery");
auto channel =
std::make_unique<flutter::MethodChannel<>>(
flutter_instance->messenger(), channel_name,
&flutter::StandardMethodCodec::GetInstance());
channel->SetMethodCallHandler(
[](const flutter::MethodCall<>& call,
std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> result) {
// cheack method name called from dart
if (call.method_name().compare("getBatteryLevel") == 0) {
int battery_level = GetBatteryLevel();
const auto* flu_value = std::get_if<int>(call.arguments());
std::cout << typeid(flu_value).name() << std::endl;
if (!flu_value) {
result->Error("Missing required type parameter","Expected int");
}
std::cout << "From Flutter: " << *flu_value << std::endl;
if (battery_level != -1) {
result->Success(battery_level);
}
else {
result->Error("UNAVAILABLE", "Battery level not available.");
}
}
else {
result->NotImplemented();
}
});
}
if I want to send multi-data like this:
Future<void> _getBatteryLevel(int fluval, int data2,...,...) ...
How should I do or parse these two values fluval and data2 when call once invokeMethod?
Any examples that I can reference? or tips for the Windows UI design?
I try to search but the most answer is for the Android or IOS app, and the android answer is using call.argument("value") which you can choose specific data value to use but the windows only has call.arguments(); function call, I don't know how to get the specific data I want.
============================================================
[Update]
From the #Richard tips and example,
I made a test and it works, thanks #Richard!
Here is the Flutter UI example code: (inside the Stateful Widget State class), fluval= 100, fluval2 = 87
String _getBackV1 = 'Unknown Value 1.';
String _getBackV2 = 'Unknown Value 2.';
int value = 100;
Future<void> _testMapPassValue(int fluval, int fluval2) async {
String backValue1, backValue2;
try {
final Map<String, dynamic>? getReply = await platform
.invokeMapMethod<String, dynamic>('testPass',
<String, dynamic>{"fluval": fluval, "fluval2": fluval2});
backValue1 = "Get Back Value 1 from windows: ${getReply!["fluval"]}";
backValue2 = "Get Back Value 2 from windows: ${getReply!["fluval2"]}";
} on PlatformException catch (e) {
backValue1 = "Failed to get Value 1: '${e.message}'.";
backValue2 = "Failed to get Value 2: '${e.message}'.";
}
setState(() {
_getBackV1 = backValue1;
_getBackV2 = backValue2;
});
}
At the Windows side example code:
using flutter::EncodableList;
using flutter::EncodableMap;
using flutter::EncodableValue;
constexpr char testMapPassValue[] = "testPass";
constexpr char passKey1[] = "fluval";
constexpr char passKey2[] = "fluval2";
The method call handler:
if (call.method_name().compare(testMapPassValue) == 0) {
const auto* getArguments_flu = std::get_if<flutter::EncodableMap>(call.arguments());
assert(getArguments_flu);
return Flu_2_Win_MethodHandler(*getArguments_flu, std::move(result));
}
void Flu_2_Win_MethodHandler(
const EncodableMap& args, std::unique_ptr<flutter::MethodResult<>> result) {
int wins2fluValue1;
int wins2fluValue2;
EncodableMap win2fluMap;
const auto* flu2winsValue1 =
std::get_if<int>(ValueOrNull(args, passKey1));
if (!flu2winsValue1) {
return result->Error("argument_error",
std::string(passKey1) + " argument missing");
}
wins2fluValue1 = *flu2winsValue1;
std::cout << "From Flutter value1: " << *flu2winsValue1 << std::endl;
wins2fluValue1 = wins2fluValue1 + 10;
std::cout << "After calculate value1: " << wins2fluValue1 << std::endl;
const auto* flu2winsValue2 =
std::get_if<int>(ValueOrNull(args, passKey2));
if (!flu2winsValue2) {
return result->Error("argument_error",
std::string(passKey2) + " argument missing");
}
wins2fluValue2 = *flu2winsValue2;
std::cout << "From Flutter value1: " << *flu2winsValue2 << std::endl;
wins2fluValue2 = wins2fluValue2 + 20;
std::cout << "After calculate value2: " << wins2fluValue2 << std::endl;
win2fluMap.insert(std::pair<std::string, int>("fluval", wins2fluValue1));
win2fluMap.insert(std::pair<std::string, int>("fluval2", wins2fluValue2));
return result->Success(std::move(EncodableValue(win2fluMap)));
}
and the final result:
Thank you!
You can only pass a single entity as argument or result, but that entity can be any of the supported types (whether primitive - int, double, etc - or complex - list or map).
The mapping between Dart and C++ (native for Windows) types is:
// std::monostate -> null
// bool -> bool
// int32_t -> int
// int64_t -> int
// double -> double
// std::string -> String
// std::vector<uint8_t> -> Uint8List
// std::vector<int32_t> -> Int32List
// std::vector<int64_t> -> Int64List
// std::vector<float> -> Float32List
// std::vector<double> -> Float64List
// EncodableList -> List
// EncodableMap -> Map
(see encodable_value.h)
So, to send your two integers (fluval and data2) you could choose to put them in a Dart list (i.e. <int>[123, 456]) or a Dart map (i.e. {'fluval':123, 'data2':456}). At the native end, arguments will be either an EncodableList or EncodableMap.
Here's an example of how a complex Dart structure would appear at the native end:
// {
// 'flag': true,
// 'name': 'Thing',
// 'values': [1, 2.0, 4],
// }
// would correspond to:
// EncodableValue(EncodableMap{
// {EncodableValue("flag"), EncodableValue(true)},
// {EncodableValue("name"), EncodableValue("Thing")},
// {EncodableValue("values"), EncodableValue(EncodableList{
// EncodableValue(1),
// EncodableValue(2.0),
// EncodableValue(4),
// })},
// })
The camera plugin has some example usage (to get the arguments as a map):
const auto* arguments = std::get_if<flutter::EncodableMap>(method_call.arguments());
In the same file, check out the two utility functions:
// Looks for |key| in |map|, returning the associated value if it is present, or
// a nullptr if not.
const EncodableValue* ValueOrNull(const EncodableMap& map, const char* key) {
auto it = map.find(EncodableValue(key));
if (it == map.end()) {
return nullptr;
}
return &(it->second);
}
// Looks for |key| in |map|, returning the associated int64 value if it is
// present, or std::nullopt if not.
std::optional<int64_t> GetInt64ValueOrNull(const EncodableMap& map,
const char* key) {
auto value = ValueOrNull(map, key);
if (!value) {
return std::nullopt;
}
if (std::holds_alternative<int32_t>(*value)) {
return static_cast<int64_t>(std::get<int32_t>(*value));
}
auto val64 = std::get_if<int64_t>(value);
if (!val64) {
return std::nullopt;
}
return *val64;
}
and their typical usage:
const auto* camera_name =
std::get_if<std::string>(ValueOrNull(args, kCameraNameKey));
auto camera_id = GetInt64ValueOrNull(args, kCameraIdKey);

Sending a string to UART gives garbage with printf

I'm trying to format data sent over a USB UART with printf and it's giving me garbage. I can send a simple string and that works but anything I try to format gives junk. Looking through the code I think it has to do with my string not being in program space but I'm not sure.
Here is my main:
void main(void) {
CPU_PRESCALE(CPU_16MHz);
init_uart();
int degree = 0;
char buffer[50];
while(1) {
degree = (degree + 1) % 360;
send_str(PSTR("\n\nHello!!!\n\n"));
memset(buffer, 0, 50);
sprintf_P(buffer, PSTR("%d degrees\n"), degree);
send_str(buffer);
_delay_ms(20);
}
}
The output looks like this:
Hello!!!
����/�������(/����#Q��������
Hello!!!
����/�������(/����#Q��������
The USB UART code I found in a tutorial. The relevant parts look like this:
void send_str(const char *s)
{
char c;
while (1) {
c = pgm_read_byte(s++);
if (!c) break;
usb_serial_putchar(c);
}
}
int8_t usb_serial_putchar(uint8_t c)
{
uint8_t timeout, intr_state;
// if we're not online (enumerated and configured), error
if (!usb_configuration) return -1;
// interrupts are disabled so these functions can be
// used from the main program or interrupt context,
// even both in the same program!
intr_state = SREG;
cli();
UENUM = CDC_TX_ENDPOINT;
// if we gave up due to timeout before, don't wait again
if (transmit_previous_timeout) {
if (!(UEINTX & (1<<RWAL))) {
SREG = intr_state;
return -1;
}
transmit_previous_timeout = 0;
}
// wait for the FIFO to be ready to accept data
timeout = UDFNUML + TRANSMIT_TIMEOUT;
while (1) {
// are we ready to transmit?
if (UEINTX & (1<<RWAL)) break;
SREG = intr_state;
// have we waited too long? This happens if the user
// is not running an application that is listening
if (UDFNUML == timeout) {
transmit_previous_timeout = 1;
return -1;
}
// has the USB gone offline?
if (!usb_configuration) return -1;
// get ready to try checking again
intr_state = SREG;
cli();
UENUM = CDC_TX_ENDPOINT;
}
// actually write the byte into the FIFO
UEDATX = c;
// if this completed a packet, transmit it now!
if (!(UEINTX & (1<<RWAL))) UEINTX = 0x3A;
transmit_flush_timer = TRANSMIT_FLUSH_TIMEOUT;
SREG = intr_state;
return 0;
}

ncurses & entering multi key characters

I'm trying to enter multi-characters in an ncurses-application (e.g. accents, special characters):
I enter before that in the terminal:
xmodmap -e "keycode 66 = Multi_key"
and then:
capslock e =
(these 3 keys) gives an euro sign: € <- there you should see an euro
sign, see https://en.wikipedia.org/wiki/Euro_sign
In the ncurses application I get garbage or the terminal seems to hang - I then need to press a couple of keys to-unhang it often that does not work.
#include <ncursesw/curses.h>
int main(int argc, char *argv[])
{
setlocale(LC_ALL,"");
initscr();
start_color();
use_default_colors();
keypad(stdscr, TRUE);
cbreak();
intrflush(stdscr, FALSE);
noecho();
refresh();
nodelay(stdscr, FALSE);
meta(stdscr, TRUE); /* enable 8-bit input */
raw(); /* to be able to catch ctrl+c */
leaveok(stdscr, TRUE);
for(;;) {
wint_t ch;
if (get_wch(&ch) != ERR) {
wchar_t temp[] = { ch, 0x00 };
addwstr(temp);
}
else {
addwstr(L" {ERR} ");
}
refresh();
}
return 0;
}
Any ideas?

Wide Char To Multi-Byte

I'm trying to convert wide char into multi-byte. It's only on yje myfile part. The rest works fine.I can't use wofstream because I am using ofstream in several places, so I am left with this.
void PrintBrowserInfo(IWebBrowser2 *pBrowser) {
BSTR bstr;
pBrowser->get_LocationURL(&bstr);
std::wstring wsURL;
wsURL = bstr;
size_t DSlashLoc = wsURL.find(L"://");
if (DSlashLoc != wsURL.npos)
{
wsURL.erase(wsURL.begin(), wsURL.begin() + DSlashLoc + 3);
}
DSlashLoc = wsURL.find(L"www.");
if (DSlashLoc == 0)
{
wsURL.erase(wsURL.begin(), wsURL.begin() + 4);
}
DSlashLoc = wsURL.find(L"/");
if (DSlashLoc != wsURL.npos)
{
wsURL.erase(DSlashLoc);
}
wprintf(L"\n URL: %s\n\n", wsURL.c_str());
char LogURL = WideCharToMultiByte( CP_ACP, WC_COMPOSITECHECK, wsURL.c_str(), -1, NULL, 0, NULL, NULL);
myfile << "\n URL:" << LogURL;
SysFreeString(bstr);
}
void EnumExplorers() {
CoInitialize(NULL);
SHDocVw::IShellWindowsPtr spSHWinds;
IDispatchPtr spDisp;
if (spSHWinds.CreateInstance(__uuidof(SHDocVw::ShellWindows)) == S_OK) {
long nCount = spSHWinds->GetCount();
for (long i = 0; i < nCount; i++) {
_variant_t va(i, VT_I4);
spDisp = spSHWinds->Item(va);
SHDocVw::IWebBrowser2Ptr spBrowser(spDisp);
if (spBrowser != NULL) {
PrintBrowserInfo((IWebBrowser2 *)spBrowser.GetInterfacePtr());
spBrowser.Release();
}
}
} else {
puts("Shell windows failed to initialise");
}
}
You're using WideCharToMultiByte wrong. You need to pass it a string buffer to receive the converted string. Using NULL and 0 as parameters as you have done will return the required size of the result string.
int length = WideCharToMultiByte (CP_ACP, WC_COMPOSITECHECK, wsURL.c_str(), -1, NULL, 0, NULL, NULL);
std::string LogURL(length+1, 0);
int result = WideCharToMultiByte (CP_ACP, WC_COMPOSITECHECK, wsURL.c_str(), -1, &LogURL[0], length+1, NULL, NULL);
You should check result for a non-zero value to make sure the function worked correctly.

Resources