File copy with progress indicator [duplicate] - objective-c

FSCopyObjectAsync is Deprecated in OS X v10.8, Now how to display progress indictor for file copy operation.

My answer assumes you're talking about showing the progress of a single file being copied.
Yes, "FSCopyObjectAsync" been deprecated but it's not gone yet.
And as you have discovered, Apple has not yet provided a useful replacement for the functionality that will eventually be removed. I suspect (but do not know for certain) that when the new functionality comes in, perhaps for 10.9, it will be delivered in the "NSFileManagerDelegate" protocol for delegates to make use of.
To make certain of that, Apple needs to be aware there are lots of developers need this. File a bug report at http://bugreporter.apple.com -- it'll likely be closed as a duplicate, but every vote counts.

copyfile(3) is alternative for FSCopyObjectAsync. Here is example of copyfile(3) with Progress Callback.

I created an open source project addressing this issue, I wrapped copy file(3) on a NSOperation and created a gui for it, please check it out and maybe contribute to make it better.
https://github.com/larod/FileCopyDemo

Coping files with progressIndicator in C
#define BUFSIZE (64*1024)
void *thread_proc(void *arg);
{
//outPath & inPatn an NSString paths
char buffer[BUFSIZE];
const char * outputFile = [outPath UTF8String];
const char * inputFile = [inPath UTF8String];
int in = open(inputFile, O_RDONLY);
int out = open(outputFile, O_WRONLY | O_CREAT | O_TRUNC);
vvolatile off_t progress;
progress = 0;
ssize_t bytes_read;
double fileSize = 0;
NSNumber * theSize;
if ([inPath getResourceValue:&theSize forKey:NSURLFileSizeKey error:nil])
fileSize = [theSize doubleValue];
[progressIndicator setMaxValue:fileSize];
while((bytes_read = read(in, buffer, BUFSIZE)) > 0)
{
write(out, buffer, BUFSIZE);
progress += bytes_read;
[progressIndicator setDoubleValue:progress];
}
// copy is done, or an error occurred
close(in);
close(out);
}

Related

TI CC2650STK - how to control onboard LED through iOS app

I am using this code from this repository: https://git.ti.com/sensortag-ios-source-code-example/sensortag-ios-source-code-example
I am trying to turn on the red onboard LED of the CC2650STK when the object temperature sensor exceeds 30°C and turn it off when the temperature is below 30°C again.
I'm not even sure if my current approach is correct but I'm stuck here. Does somebody know what I'm doing wrong?
Thanks in advance!
I did not change the hardware's firmware
I have already added the following into the "calcValue" method in the 'sensorTagAmbientTemperatureService.m' file:
if (tObj >= 30.0){
uint8_t valueRedLedOn = 0x01;
NSData *data = [NSData dataWithBytes:&valueRedLedOn length:sizeof(valueRedLedOn)];
[self.btHandle writeValue:data toCharacteristic:TI_SENSORTAG_IO_CONFIG];
redLedOn = true;
}
else {
if(redLedOn == true){
uint8_t valueRedLedOff = 0x00;
NSData *data = [NSData dataWithBytes:&valueRedLedOff length:sizeof(valueRedLedOn)];
[self.btHandle writeValue:data toCharacteristic:TI_SENSORTAG_IO_CONFIG];
redLedOn = false;
}
}
but when the app is running and the temperature reaches 30°C, I get a SIGABRT error (also see the log output):
screenshot of error w code and log
repository with my changes
Thanks for your answers.
I got to fix it.
The problem was that I forgot to initialize the service and characteristic.
I added 'sensorTagIoService.h' and '.m' and initialized it like the other services.
(the values for LED on and off in my question seem to be wrong tho)

Write UART on PIC18

I need help with the uart communication I am trying to implement on my Proteus simulation. I use a PIC18f4520 and I want to display on the virtual terminal the values that have been calculated by the microcontroller.
Here a snap of my design on Proteus
Right now, this is how my UART code looks like :
#define _XTAL_FREQ 20000000
#define _BAUDRATE 9600
void Configuration_ISR(void) {
IPR1bits.TMR1IP = 1; // TMR1 Overflow Interrupt Priority - High
PIE1bits.TMR1IE = 1; // TMR1 Overflow Interrupt Enable
PIR1bits.TMR1IF = 0; // TMR1 Overflow Interrupt Flag
// 0 = TMR1 register did not overflow
// 1 = TMR1 register overflowed (must be cleared in software)
RCONbits.IPEN = 1; // Interrupt Priority High level
INTCONbits.PEIE = 1; // Enables all low-priority peripheral interrupts
//INTCONbits.GIE = 1; // Enables all high-priority interrupts
}
void Configuration_UART(void) {
TRISCbits.TRISC6 = 0;
TRISCbits.TRISC7 = 1;
SPBRG = ((_XTAL_FREQ/16)/_BAUDRATE)-1;
//RCSTA REG
RCSTAbits.SPEN = 1; // enable serial port pins
RCSTAbits.RX9 = 0;
//TXSTA REG
TXSTAbits.BRGH = 1; // fast baudrate
TXSTAbits.SYNC = 0; // asynchronous
TXSTAbits.TX9 = 0; // 8-bit transmission
TXSTAbits.TXEN = 1; // enble transmitter
}
void WriteByte_UART(unsigned char ch) {
while(!PIR1bits.TXIF); // Wait for TXIF flag Set which indicates
// TXREG register is empty
TXREG = ch; // Transmitt data to UART
}
void WriteString_UART(char *data) {
while(*data){
WriteByte_UART(*data++);
}
}
unsigned char ReceiveByte_UART(void) {
if(RCSTAbits.OERR) {
RCSTAbits.CREN = 0;
RCSTAbits.CREN = 1;
}
while(!PIR1bits.RCIF); //Wait for a byte
return RCREG;
}
And in the main loop :
while(1) {
WriteByte_UART('a'); // This works. I can see the As in the terminal
WriteString_UART("Hello World !"); //Nothing displayed :(
}//end while(1)
I have tried different solution for WriteString_UART but none has worked so far.
I don't want to use printf cause it impacts other operations I'm doing with the PIC by adding delay.
So I really want to make it work with WriteString_UART.
In the end I would like to have someting like "Error rate is : [a value]%" on the terminal.
Thanks for your help, and please tell me if something isn't clear.
In your WriteByte_UART() function, try polling the TRMT bit. In particular, change:
while(!PIR1bits.TXIF);
to
while(!TXSTA1bits.TRMT);
I don't know if this is your particular issue, but there exists a race-condition due to the fact that TXIF is not immediately cleared upon loading TXREG. Another option would be to try:
...
Nop();
while(!PIR1bits.TXIF);
...
EDIT BASED ON COMMENTS
The issue is due to the fact that the PIC18 utilizes two different pointer types based on data memory and program memory. Try changing your declaration to void WriteString_UART(const rom char * data) and see what happens. You will need to change your WriteByte_UART() declaration as well, to void WriteByte_UART(const unsigned char ch).
Add delay of few miliseconds after line
TXREG = ch;
verify that pointer *data of WriteString_UART(char *data) actually point to
string "Hello World !".
It seems you found a solution, but the reason why it wasn't working in the first place is still not clear. What compiler are you using?
I learned the hard way that C18 and XC8 are used differently regarding memory spaces. With both compilers, a string declared literally like char string[]="Hello!", will be stored in ROM (program memory). They differ in the way functions use strings.
C18 string functions will have variants to access strings either in RAM or ROM (for example strcpypgm2ram, strcpyram2pgm, etc.). XC8 on the other hand, does the job for you and you will not need to use specific functions to choose which memory you want to access.
If you are using C18, I would highly recommend you switch to XC8, which is more recent and easier to work with. If you still want to use C18 or another compiler which requires you to deal with program/data memory spaces, then here below are two solutions you may want to try. The C18 datasheet says that putsUSART prints a string from data memory to USART. The function putrsUSART will print a string from program memory. So you can simply use putrsUSART to print your string.
You may also want to try the following, which consists in copying your string from program memory to data memory (it may be a waste of memory if your application is tight on memory though) :
char pgmstring[] = "Hello";
char datstring[16];
strcpypgm2ram(datstring, pgmstring);
putsUSART(datstring);
In this example, the pointers pgmstring and datstring will be stored in data memory. The string "Hello" will be stored in program memory. So even if the pointer pgmstring itself is in data memory, it initially points to a memory address (the address of "Hello"). The only way to point to this same string in data memory is to create a copy of it in data memory. This is because a function accepting a string stored in data memory (such as putsUSART) can NOT be used directly with a string stored in program memory.
I hope this could help you understand a bit better how to work with Harvard microprocessors, where program and data memories are separated.

OSX Serial read freeze / hang

I'm writing a serial communication wrapper class in Objective-C. To list all serial available modems and setup the connection I'm using pretty much the same code as used in this example project by Apple.
I could read and write the ways apple does it. But I want to implement a loop on a second thread and write to the stream if a NSString *writeString longer 0 and read after write if bytes are available.
I got writing working quite straight forward. I just used the write function declared in unistd.h.
Reading will not work. Whenever I call read(), the function hangs and my loop does not proceed.
Here is the code used in my loop:
- (void)runInCOMLoop {
do {
// write
} while (bytesWritten < strlen([_writeString UTF8String]));
NSMutableString *readString = [NSMutableString string];
ssize_t bytesRead = 0;
ssize_t readB = 0;
char buffer[256];
do {
readB = read(_fileDescriptor, &buffer, sizeof(buffer));
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this function hangs
bytesRead += readB;
if (readB == -1 {
// error
}
else if (readB > 0) {
if(buffer[bytesRead - 1] == '\r' ]] buffer[bytesRead - 1] == '\n') {
break;
}
[readString appendString:[NSString stringWithUTF8String:buffer]];
}
} while (readB > 0);
What am I doing wrong here?
read() will block if there is nothing to read. Apple probably has their own of doing things, but you can use select() to see if there is anything to read on _fileDescriptor. Google around for examples on how to use select.
Here's one link on StackOverflow:
Can someone give me an example of how select() is alerted to an fd becoming "ready"
This excerpt from the select man is pertains:
To effect a poll, the timeout argument should be
non-nil, pointing to a zero-valued timeval structure. Timeout is not
changed by select(), and may be reused on subsequent calls, however it is
good style to re-initialize it before each invocation of select().
You can set the non-blocking flag (O_NONBLOCK) on the file descriptor using fcntl() to keep read() from waiting for data, but if you do that, you have to continuously poll looking for data, which is obviously bad from a CPU usage standpoint. As Charlie Burns' answer explains, the best solution is to use select() which will allow your program to efficiently wait until there is some data to be read on the port's file descriptor. Here's some example code taken from my own Objective-C serial port class, ORSSerialPort (slightly modified):
fd_set localReadFDSet;
FD_ZERO(&localReadFDSet);
FD_SET(self.fileDescriptor, &localReadFDSet);
timeout.tv_sec = 0;
timeout.tv_usec = 100000; // Check to see if port closed every 100ms
result = select(localPortFD+1, &localReadFDSet, NULL, NULL, &timeout);
if (!self.isOpen) break; // Port closed while select call was waiting
if (result < 0) {
// Handle error
}
if (result == 0 || !FD_ISSET(localPortFD, &localReadFDSet)) continue;
// Data is available
char buf[1024];
long lengthRead = read(localPortFD, buf, sizeof(buf));
NSData *readData = nil;
if (lengthRead>0) readData = [NSData dataWithBytes:buf length:lengthRead];
Note that select() indicates that data is available by returning. So, your program will sit suspended at the select() call while no data is available. The program is not hung, that's how it's supposed to work. If you need to do other things while select() is waiting, you should put the select() call on a different queue/thread from the other work you need to do. ORSSerialPort does this.

Best way to know if application is inactive in cocoa mac OSX?

So, i am building a program that will stand on a exhibition for public usage, and i got a task to make a inactive state for it. Just display some random videos from a folder on the screen, like a screensaver but in the application.
So what is the best and proper way of checking if the user is inactive?
What i am thinking about is some kind of global timer that gets reset on every user input and if it reaches lets say 1 minute it goes into inactive mode. Are there any better ways?
You can use CGEventSourceSecondsSinceLastEventType
Returns the elapsed time since the last event for a Quartz event
source.
/*
To get the elapsed time since the previous input event—keyboard, mouse, or tablet—specify kCGAnyInputEventType.
*/
- (CFTimeInterval)systemIdleTime
{
CFTimeInterval timeSinceLastEvent = CGEventSourceSecondsSinceLastEventType(kCGEventSourceStateHIDSystemState, kCGAnyInputEventType);
return timeSinceLastEvent;
}
I'm expanding on Parag Bafna's answer. In Qt you can do
#include <ApplicationServices/ApplicationServices.h>
double MyClass::getIdleTime() {
CFTimeInterval timeSinceLastEvent = CGEventSourceSecondsSinceLastEventType(kCGEventSourceStateHIDSystemState, kCGAnyInputEventType);
return timeSinceLastEvent;
}
You also have to add the framework to your .pro file:
QMAKE_LFLAGS += -F/System/Library/Frameworks/ApplicationServices.framework
LIBS += -framework ApplicationServices
The documentation of the function is here
I've found a solution that uses the HID manager, this seems to be the way to do it in Cocoa. (There's another solution for Carbon, but it doesn't work for 64bit OS X.)
Citing Daniel Reese on the Dan and Cheryl's Place blog:
#include <IOKit/IOKitLib.h>
/*
Returns the number of seconds the machine has been idle or -1 on error.
The code is compatible with Tiger/10.4 and later (but not iOS).
*/
int64_t SystemIdleTime(void) {
int64_t idlesecs = -1;
io_iterator_t iter = 0;
if (IOServiceGetMatchingServices(kIOMasterPortDefault,
IOServiceMatching("IOHIDSystem"),
&iter) == KERN_SUCCESS)
{
io_registry_entry_t entry = IOIteratorNext(iter);
if (entry) {
CFMutableDictionaryRef dict = NULL;
kern_return_t status;
status = IORegistryEntryCreateCFProperties(entry,
&dict,
kCFAllocatorDefault, 0);
if (status == KERN_SUCCESS)
{
CFNumberRef obj = CFDictionaryGetValue(dict,
CFSTR("HIDIdleTime"));
if (obj) {
int64_t nanoseconds = 0;
if (CFNumberGetValue(obj,
kCFNumberSInt64Type,
&nanoseconds))
{
// Convert from nanoseconds to seconds.
idlesecs = (nanoseconds >> 30);
}
}
CFRelease(dict);
}
IOObjectRelease(entry);
}
IOObjectRelease(iter);
}
return idlesecs;
}
The code has been slightly modified, to make it fit into the 80-character limit of stackoverflow.
This might sound like a silly question; but why not just set up a screensaver, with a short fuse?
You can listen for the NSNotification named #"com.apple.screensaver.didstart" if you need to do any resets or cleanups when the user wanders away.
Edit: You could also set up the screen saver; wait for it to fire, and then do your own thing when it starts, stopping the screen saver when you display your own videos; but setting up a screen saver the proper way is probably a good idea.
Take a look at UKIdleTimer, maybe it's what you're looking for.

Determine if a network share exists before mounting

I'm working on a tool to automatically mount network volumes based on what wireless network the user is connected to. Mounting the volume is easy:
NSURL *volumeURL = /* The URL to the network volume */
// Attempt to mount the volume
FSVolumeRefNum volumeRefNum;
OSStatus error = FSMountServerVolumeSync((CFURLRef)volumeURL, NULL, NULL, NULL, &volumeRefNum, 0L);
However, if there is no network share at volumeURL (if someone turned off or removed a network hard drive, for example), Finder pops up an error message explaining this fact. My goal is for this not to happen — I'd like to attempt to mount the volume, but fail silently if mounting fails.
Does anyone have any tips on how to do this? Ideally, I'd like to find a way to check if the share exists before attempting to mount it (so as to avoid unnecessary work). If that's not possible, some way to tell the Finder not to display its error message would work as well.
This answer uses Private Frameworks. As naixn points out in the comments, this means it could break even on a dot release.
There is no way to do this using only public API (that I can find after a couple of hours of searching/disassembling).
This code will access the URL and not display any UI elements pass or fail. This includes not only errors, but authentication dialogs, selection dialogs, etc.
Also, it's not Finder displaying those messages, but NetAuthApp from CoreServices. The function being called here (netfs_MountURLWithAuthenticationSync) is called directly from the function in the question (FSMountServerVolumeSync). Calling it at this level lets us pass the kSuppressAllUI flag.
On success, rc is 0 and mountpoints contains a list of NSStrings of the mounted directories.
//
// compile with:
//
// gcc -o test test.m -framework NetFS -framework Foundation
include <inttypes.h>
#include <Foundation/Foundation.h>
// Calls to FSMountServerVolumeSync result in kSoftMount being set
// kSuppressAllUI was found to exist here:
// http://www.opensource.apple.com/source/autofs/autofs-109.8/mount_url/mount_url.c
// its value was found by trial and error
const uint32_t kSoftMount = 0x10000;
const uint32_t kSuppressAllUI = 0x00100;
int main(int argc, char** argv)
{
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
NSURL *volumeURL = [NSURL URLWithString:#"afp://server/path"];
NSArray* mountpoints = nil;
const uint32_t flags = kSuppressAllUI | kSoftMount;
const int rc = netfs_MountURLWithAuthenticationSync((CFURLRef)volumeURL, NULL, NULL,
NULL, flags, (CFArrayRef)&mountpoints);
NSLog(#"mountpoints: %#; status = 0x%x", mountpoints, rc);
[pool release];
}